我不知道如何计算泛型lambda的所有参数[编辑:但Yuri Kilochek知道如何做到:请查看他的答案以获取一个伟大的解决方案]。对于非泛型lambda,可以像Igor Tandetnik建议的那样,检测指向
operator()
的指针的类型(返回值和参数)并计算参数个数。以下是示例内容:
template <typename R, typename T, typename ... Args>
constexpr std::size_t cah (R(T::*)(Args...) const)
{ return sizeof...(Args); }
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;
template <typename T>
constexpr std::false_type ipvh (...);
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”进行检查时
Original Answer翻译成"最初的回答"
auto lambda_variadic2 = [&](std::string, auto... args){ ... };
虽然这是可变参数函数,但第一个参数不接受int
,因此无法被识别为“纯可变参数函数”;不幸的是,下面的lambda表达式
Original Answer翻译成:最初的回答
auto lambda_variadic3 = [&](long, auto... args){ ... };
因为第一个参数接受一个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; }
另一个问题是,当检测到接收高于已检查数量(例如50)的参数的非变参通用lambda函数时,它们也被视为“纯虚函数”。
而且,这个解决方案无法检测出lambda_variadic2(一个非纯变参lambda)是否为变参函数。
以下是我能想到的最佳答案的完整编译示例。
#include <iostream>
#include <utility>
#include <type_traits>
template <typename R, typename T, typename ... Args>
constexpr std::size_t cah (R(T::*)(Args...) const)
{ return sizeof...(Args); }
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;
template <typename T>
constexpr std::false_type ipvh (...);
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 << isPureVariadic(lambda0) << std::endl;
std::cout << isPureVariadic(lambda1) << std::endl;
std::cout << isPureVariadic(lambda2) << std::endl;
std::cout << isPureVariadic(lambda3) << std::endl;
}
operator()
的类)。但是我还不确定如何将其扩展到其他情况。 - Igor Tandetnik