使用模板元编程检测函数可以采用的最大参数数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用模板元编程检测函数可以采用的最大参数数相关的知识,希望对你有一定的参考价值。

请考虑以下代码:

template <class T, class F>
std::size_t maximum_number_of_arguments(F&& f) {
    // Code here
}

我想要一个函数,可以找到可调用T可以采用的f类型的最大参数数。

例如,对于以下重载集:

void f(int, int); // f called with 2 ints compiles
void f(int, int, int); // f called with 3 ints compiles
void f(int, char, int, double); // f called with 4 ints compiles
void f(int, std::string, int, int, int); // f called with 5 ints does not compile

结果是:

maximum_number_of_arguments<int>(f)

应该返回4

我猜想修复一个函数可以采用的限制数量参数的方法(例如256),并测试所有可能性,并跟踪无法编译的调用。如何使用template / contexpr元编程实现这一点?

编辑:回答有关我们无法将重载集传递给函数的事实的评论(我的f示例可能不是最好的):

#include <iostream>

struct functor
{
    void operator()(int) {std::cout << "int" << std::endl;}
    void operator()(int, int) {std::cout << "int, int" << std::endl;}
    void operator()(int, int, int) {std::cout << "int, int, int" << std::endl;}
};

template <class F>
void caller(F&& f)
{
    std::forward<F>(f)(1);
    std::forward<F>(f)(1, 2);
    std::forward<F>(f)(1, 2, 3);
}

int main(int argc, char* argv[])
{
    functor f;
    caller(f);
    return 0;
}
答案

你问的不是微不足道的......

如果您对单独可用于调用函数或具有公共标识符的一组函数的最大整数数感兴趣,则排除其他类型的调用...

我的意思是......如果检查下面的f()函数

void f(int, int); 
void f(int, char, int);
void f(int, std::string, int, int, int); // excluded by std::string

应该得到3因为接收std::string的版本将被排除...

嗯...用宏(所以我的解决方案是内在的邪恶)定义一个专用于符号的检查结构

setMaxStruct(f);

您可以获得最大数量的整数参数(具有可设置但默认的最大值),编写如下内容

std::cout << "--- f: " << getMaxArgsFor_f<int>::value << std::endl;

以下是一个完整的工作示例

#include <utility>
#include <iostream>
#include <type_traits>

template <typename T, std::size_t>
using typer = T;

#define setMaxStruct(func)                                        
                                                                  
template <typename Type, std::size_t MaxArgs = 64U>               
struct getMaxArgsFor_ ## func                                     
 {                                                                
   template <typename, std::size_t ...>                           
   static std::false_type isCallable (...);                       
                                                                  
   template <typename T, std::size_t ... Is>                      
   static auto isCallable (int)                                   
      -> decltype( func(std::declval<typer<T, Is>>()...),         
                   std::true_type{} );                            
                                                                  
   template <typename T, std::size_t ... Is>                      
   static constexpr bool getMaxTH3                                
      (std::index_sequence<Is...> const &)                        
    { return decltype(isCallable<T, Is...>(0))::value; }          
                                                                  
   template <typename T, std::size_t I>                           
   static constexpr bool getMaxTH2 ()                             
    { return getMaxTH3<T>(std::make_index_sequence<I>{}); }       
                                                                  
   template <typename T, std::size_t ... Is>                      
   static constexpr std::size_t getMaxTH1                         
      (std::index_sequence<Is...> const &)                        
    {                                                             
      std::size_t ret ( -1 );                                     
                                                                  
      ( (ret = getMaxTH2<T, Is>() ? Is : ret), ...);              
                                                                  
      return ret;                                                 
    }                                                             
                                                                  
   template <typename T, std::size_t MaxAs>                       
   static constexpr std::size_t getMaxT ()                        
    { return getMaxTH1<T>(std::make_index_sequence<MaxAs>{}); }   
                                                                  
   static constexpr std::size_t value = getMaxT<Type, MaxArgs>(); 
 }

void f(int, int);
void f(int, int, int);
void f(int, char, int, double);
void f(int, std::string, int, int, int);

template <typename ... Args>
void h (Args ... args);

setMaxStruct(f);
setMaxStruct(g);
setMaxStruct(h);

int main()
 {
   std::cout << "--- f: " << getMaxArgsFor_f<int>::value << std::endl;
   std::cout << "--- g: " << getMaxArgsFor_g<int>::value << std::endl;
   std::cout << "--- h: " << getMaxArgsFor_h<int>::value << std::endl;
 }

观察来自f,你得到4,从g你得到size_t(-1)g()未定义)和从h()你得到63(最大值减去1)。

以上是关于使用模板元编程检测函数可以采用的最大参数数的主要内容,如果未能解决你的问题,请参考以下文章

Python 函数中的最大参数数是多少?

可以在C ++中使用动态分配的参数数创建函数吗?

每个数据库提供程序类型允许的最大参数数是多少?

C++ Primer 5th笔记(chap 16 模板和泛型编程)模板实参推断

模板与泛型编程——模板实参推断

函数(方法)