C++ SFINAE 确定函数参数的数量 (C++17)
C++ SFINAE to determine the number of function arguments (C++17)
我使用 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>()));
};
这是它的行为方式
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!
}
完整代码(还有几个示例)在这个 git 存储库中:https://github.com/crosetto/has_args/blob/main/number_of_arguments.cpp
有人能解释为什么这不适用于 lambda 吗?
正如@rafix07 在评论中指出的那样,这里的问题是 lambda 返回 void,因此它的签名在 test
的第一个定义中不匹配,并回退到另一个重载.一种解决方法是将逗号运算符应用于 val
的参数,即更改
static auto test(F, decltype(val(std::declval<F>()( Args ... ))), std::integer_sequence<int, Args ...>)
进入
static auto test(F, decltype(val((std::declval<F>()( Args ... ),0))), std::integer_sequence<int, Args ...>)
或者,正如@Jarod42 在评论中指出的那样, val
是不必要的,可以这样写:
static auto test(F, decltype(((std::declval<F>()( Args ... ),void(),0))), std::integer_sequence<int, Args ...>)
请注意,函数体已被解析,任何使用不能用整数编译的参数都会导致编译器错误。我认为这不能以通用方式解决(尽管可以使用 int 以外的假类型,并使其满足要求 API)。
我使用 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>()));
};
这是它的行为方式
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!
}
完整代码(还有几个示例)在这个 git 存储库中:https://github.com/crosetto/has_args/blob/main/number_of_arguments.cpp
有人能解释为什么这不适用于 lambda 吗?
正如@rafix07 在评论中指出的那样,这里的问题是 lambda 返回 void,因此它的签名在 test
的第一个定义中不匹配,并回退到另一个重载.一种解决方法是将逗号运算符应用于 val
的参数,即更改
static auto test(F, decltype(val(std::declval<F>()( Args ... ))), std::integer_sequence<int, Args ...>)
进入
static auto test(F, decltype(val((std::declval<F>()( Args ... ),0))), std::integer_sequence<int, Args ...>)
或者,正如@Jarod42 在评论中指出的那样, val
是不必要的,可以这样写:
static auto test(F, decltype(((std::declval<F>()( Args ... ),void(),0))), std::integer_sequence<int, Args ...>)
请注意,函数体已被解析,任何使用不能用整数编译的参数都会导致编译器错误。我认为这不能以通用方式解决(尽管可以使用 int 以外的假类型,并使其满足要求 API)。