我不知道如何计算泛型 lambda 的所有参数 [编辑:但 yuri Kilochek 知道如何做到这一点:请参阅他的答案以获得一个很好的解决方案]。
对于非泛型 lambda,正如 Igor Tandetnik 所建议的,您可以检测指针的类型(返回和参数)operator()
并计算参数。
如下
// count arguments helper
template <typename R, typename T, typename ... Args>
constexpr std::size_t cah (R(T::*)(Args...) const)
{ return sizeof...(Args); }
// count arguments helper
template <typename R, typename T, typename ... Args>
constexpr std::size_t cah (R(T::*)(Args...))
{ return sizeof...(Args); }
template <typename L>
constexpr auto countArguments (L)
{ return cah(&L::operator()); }
但是,不幸的是,这在您引入参数时不起作用,auto
因为使用auto
参数,您可以operator()
在模板函数中进行转换。
关于检测可变参数 lambda,您可以检测一个仅具有可变参数列表的函数(让我称之为“纯可变参数”),作为您的lambda_variadic
,尝试用零和(例如)给定类型的 50 个参数调用它.
我的意思如下
template <typename T, std::size_t>
struct getType
{ using type = T; };
template <typename T, std::size_t N>
using getType_t = typename getType<T, N>::type;
// isPureVariadic arguments helper
template <typename T>
constexpr std::false_type ipvh (...);
// isPureVariadic arguments helper
template <typename T, typename F, std::size_t ... Is>
constexpr auto ipvh (F f, std::index_sequence<Is...>)
-> decltype( f(std::declval<getType_t<T, Is>>()...), std::true_type{} );
template <typename F>
constexpr bool isPureVariadic (F f)
{ return
decltype(ipvh<int>(f, std::make_index_sequence<0u>{}))::value
&& decltype(ipvh<int>(f, std::make_index_sequence<50u>{}))::value; }
但这并不完美,因为会产生误报和误报。
一个问题是,当您使用“非纯可变参数 lambda”检查它时
auto lambda_variadic2 = [&](std::string, auto... args){ ... };
那是可变参数,但第一个参数不接受 a int
,不被检测为“纯可变参数”;不幸的是,下面的 lambda
auto lambda_variadic3 = [&](long, auto... args){ ... };
被检测为“纯可变参数”,因为第一个参数接受 a int
。
为避免此问题,您可以修改函数以检查具有两种不兼容类型的 50 个参数的调用;举例
template <typename F>
constexpr bool isPureVariadic (F f)
{ return
decltype(ipvh<int>(f, std::make_index_sequence<0u>{}))::value
&& decltype(ipvh<int>(f, std::make_index_sequence<50u>{}))::value
&& decltype(ipvh<std::string>(f, std::make_index_sequence<50u>{}))::value; }
另一个问题是被检测为“纯虚拟”的非可变泛型 lambda 函数接收的参数数量高于检查的数量(在示例中为 50)。
并且仍然存在此解决方案未将lambda_variadic2
(非纯可变参数 lambda)检测为可变参数的问题。
以下是一个完整的编译示例,是我能想象到的关于您的问题的最佳示例
#include <iostream>
#include <utility>
#include <type_traits>
// count arguments helper
template <typename R, typename T, typename ... Args>
constexpr std::size_t cah (R(T::*)(Args...) const)
{ return sizeof...(Args); }
// count arguments helper
template <typename R, typename T, typename ... Args>
constexpr std::size_t cah (R(T::*)(Args...))
{ return sizeof...(Args); }
template <typename L>
constexpr auto countArguments (L)
{ return cah(&L::operator()); }
template <typename T, std::size_t>
struct getType
{ using type = T; };
template <typename T, std::size_t N>
using getType_t = typename getType<T, N>::type;
// isPureVariadic arguments helper
template <typename T>
constexpr std::false_type ipvh (...);
// isPureVariadic arguments helper
template <typename T, typename F, std::size_t ... Is>
constexpr auto ipvh (F f, std::index_sequence<Is...>)
-> decltype( f(std::declval<getType_t<T, Is>>()...), std::true_type{} );
template <typename F>
constexpr bool isPureVariadic (F f)
{ return
decltype(ipvh<int>(f, std::make_index_sequence<0u>{}))::value
&& decltype(ipvh<int>(f, std::make_index_sequence<50u>{}))::value; }
int main() {
auto lambda0 = [&]() {};
auto lambda1 = [&](int) {};
auto lambda2 = [&](int, auto) {};
auto lambda3 = [&](auto...) {};
std::cout << countArguments(lambda0) << std::endl;
std::cout << countArguments(lambda1) << std::endl;
// std::cout << countArguments(lambda2) << std::endl; // compilation error
// std::cout << countArguments(lambda3) << std::endl; // compilation error
std::cout << isPureVariadic(lambda0) << std::endl;
std::cout << isPureVariadic(lambda1) << std::endl;
std::cout << isPureVariadic(lambda2) << std::endl;
std::cout << isPureVariadic(lambda3) << std::endl;
}