C++ C++;SFINAE确定函数参数的数量(C+;+;17)

C++ C++;SFINAE确定函数参数的数量(C+;+;17),c++,c++17,template-meta-programming,sfinae,C++,C++17,Template Meta Programming,Sfinae,我使用SFINAE创建了一个元函数,以确定编译时函数的参数数量。当与函数对象一起使用时,它可以与gcc配合使用,但不能与lambda闭包配合使用,我不明白为什么。下面是元函数 template < typename T > int val (T &&){return 0;}; template <int N, typename Functor> struct has_args { template <typename F , int ...

我使用SFINAE创建了一个元函数,以确定编译时函数的参数数量。当与函数对象一起使用时,它可以与gcc配合使用,但不能与lambda闭包配合使用,我不明白为什么。下面是元函数

template < typename T >
int val (T &&){return 0;};

template <int N, typename Functor>
struct has_args {

  template <typename F , int ... Args>
  static auto test(F, decltype(val(std::declval<F>()( Args ... ))), std::integer_sequence<int, Args ...>){
          return std::true_type{};
      };

  template <typename F, typename Val, typename Seq>
  static auto test(F, Val, Seq){
          return std::false_type{};
      };

  using type =  decltype (test(std::declval<Functor>(), 0, std::make_integer_sequence<int, N>()));
};
模板
int val(T&&{返回0;};
模板
结构具有参数{
模板
静态自动测试(F,decltype(val(std::declval()(Args…)),std::integer_序列){
返回std::true_type{};
};
模板
静态自动测试(F、Val、Seq){
返回std::false_type{};
};
使用type=decltype(测试(std::declval(),0,std::make_integer_sequence());
};
下面是它应该如何表现

struct func{
    template<typename T>
    int operator()(T){}
};
int main(){

  auto lambda0 = [](auto arg){};

  static_assert(has_arg<1, func>::type::value==true, "error");
  //static_assert(has_arg<1, decltype(lambda0)>::type::value==true, "error"); // Assertion fails!
}

struct func{
模板
int运算符()(T){}
};
int main(){
自动lambda0=[](自动参数){};
静态断言(has_arg::type::value==true,“error”);
//静态断言(has_arg::type::value==true,“error”);//断言失败!
}
完整的代码(还有几个例子)在这个git repo中:


有人解释过为什么lambda不能使用它吗?

正如@rafix07在评论中指出的,这里的问题是lambda返回void,因此它的签名在
test
的第一个定义中不匹配,并返回到另一个重载。一种修复方法是对
val
的参数应用逗号运算符,即更改

static auto test(F, decltype(val(std::declval<F>()( Args ... ))), std::integer_sequence<int, Args ...>)

请注意,函数体会被解析,任何使用不使用整数编译的参数都会导致编译器错误。我认为这不能用通用的方法解决(可以使用int以外的伪类型,并使其满足所需的API)。

func
vs
func
?这是打字错误吗?请确保您发布的代码确实再现了您描述的问题,因为发布的代码是一个错误(但不是问题所涉及的错误),Lambda没有
返回
语句。所以返回类型是
void
。您想如何将
void
0
的类型匹配。使用
return int{}
可以很好地匹配。或者
decltype(val(std::declval()(Args…),void(),42)
。谢谢@rafix07,没错,我会使用
val(..,void(),0)
(或者直接(
,void(),0
)为了处理可能出现的运算符逗号重载问题。感谢@Jarold42的反馈,我认为在您的评论中您遗漏了一个额外的括号,
val((…,void(),0))
,对吗?。它仍然存在一个问题,我想这个问题是无法解决的:函数体被解析,任何使用不使用整数编译的参数都会导致编译器错误。是的,的确如此。但正如我试图强调的那样,
val
是不需要的。这是OP的一种变通方法,它不处理
void
返回类型。逗号运算符可以解决这个问题。当然,我也会在答案中添加您的备注
static auto test(F, decltype(val((std::declval<F>()( Args ... ),0))), std::integer_sequence<int, Args ...>)
static auto test(F, decltype(((std::declval<F>()( Args ... ),void(),0))), std::integer_sequence<int, Args ...>)