我需要知道lambda有多少个论点。我不喜欢他们的类型,我只需要数一数。
auto lambda0 = [&]() { ... };
auto lambda1 = [&](int32_t a) { ... };
auto lambda2 = [&](int32_t a, auto b) { ... };
lambda_details<decltype(lambda0)>::argument_count; // Equals 0
lambda_details<decltype(lambda1)>::argument_count; // Equals 1
lambda_details<decltype(lambda2)>::argument_count; // Equals 2检测不同的兰巴达也会很好,这样我也可以处理边缘的情况。
auto lambda_variadic = [&](auto... args){ ... };
lambda_details<decltype(lambda_variadic)>::is_variadic; // Equals true我怎样才能得到这些信息?
发布于 2019-01-28 00:23:59
我用@yuri kilochek的答案的修改版本解决了这个问题。
我们不是从50个参数开始,然后倒数,而是从零开始,然后向上计数。当我们得到匹配时,我们知道调用lambda所需的最小参数数。然后,我们继续搜索,直到找到一个正常的最大值,以查看是否存在最大数量的参数(这可能发生在您有默认参数时)。
如果达到了参数计数的极限,我们假设lambda是可变的。
此实现大大减少了非变量lambdas的模板实例化量。它还给出了所有lambdas的最小参数量,以及任何非变量lambdas的最大参数量。
再次感谢Yuri Kilochek为这一优雅的解决方案奠定了基础。有关实现的更多细节,请查看他的回答。
struct any_argument
{
template <typename T>
operator T && () const;
};
template <typename Lambda, typename Is, typename = void>
struct can_accept_impl : std::false_type
{};
template <typename Lambda, std::size_t ...Is>
struct can_accept_impl <Lambda, std::index_sequence<Is...>, decltype(std::declval<Lambda>()(((void)Is, any_argument{})...), void())> : std::true_type
{};
template <typename Lambda, std::size_t N>
struct can_accept : can_accept_impl<Lambda, std::make_index_sequence<N>>
{};
template <typename Lambda, std::size_t N, size_t Max, typename = void>
struct lambda_details_maximum
{
static constexpr size_t maximum_argument_count = N - 1;
static constexpr bool is_variadic = false;
};
template <typename Lambda, std::size_t N, size_t Max>
struct lambda_details_maximum<Lambda, N, Max, std::enable_if_t<can_accept<Lambda, N>::value && (N <= Max)>> : lambda_details_maximum<Lambda, N + 1, Max>
{};
template <typename Lambda, std::size_t N, size_t Max>
struct lambda_details_maximum<Lambda, N, Max, std::enable_if_t<can_accept<Lambda, N>::value && (N > Max)>>
{
static constexpr bool is_variadic = true;
};
template <typename Lambda, std::size_t N, size_t Max, typename = void>
struct lambda_details_minimum : lambda_details_minimum<Lambda, N + 1, Max>
{
static_assert(N <= Max, "Argument limit reached");
};
template <typename Lambda, std::size_t N, size_t Max>
struct lambda_details_minimum<Lambda, N, Max, std::enable_if_t<can_accept<Lambda, N>::value>> : lambda_details_maximum<Lambda, N, Max>
{
static constexpr size_t minimum_argument_count = N;
};
template <typename Lambda, size_t Max = 50>
struct lambda_details : lambda_details_minimum<Lambda, 0, Max>
{};需要注意的另一件重要的事情是,any_argument不会自动与操作符保持良好关系。如果希望使用操作的auto参数(例如,[](auto a) { return a * 2; }),则必须重载每一个参数。它最终会看起来更像这样:
struct any_argument
{
template <typename T> operator T && () const;
any_argument& operator ++();
any_argument& operator ++(int);
any_argument& operator --();
any_argument& operator --(int);
template <typename T> friend any_argument operator + (const any_argument&, const T&);
template <typename T> friend any_argument operator + (const T&, const any_argument&);
template <typename T> friend any_argument operator - (const any_argument&, const T&);
template <typename T> friend any_argument operator - (const T&, const any_argument&);
template <typename T> friend any_argument operator * (const any_argument&, const T&);
template <typename T> friend any_argument operator * (const T&, const any_argument&);
template <typename T> friend any_argument operator / (const any_argument&, const T&);
template <typename T> friend any_argument operator / (const T&, const any_argument&);
// And every other operator in existence
};发布于 2019-01-27 18:52:36
您可以创建一个可以通过重载转换运算符进入任何参数的对象。从那里开始,只需测试lambda是否可以用给定数量的此类参数调用,从任意的大数中进行计数。如果lambda在第一次尝试时碰巧是可调用的(给定了大量的参数),我们可以假设它是可变的:
#include <iostream>
#include <utility>
#include <type_traits>
struct any_argument {
template <typename T>
operator T&&() const;
};
template <typename Lambda, typename Is, typename = void>
struct can_accept_impl
: std::false_type
{};
template <typename Lambda, std::size_t ...Is>
struct can_accept_impl<Lambda, std::index_sequence<Is...>,
decltype(std::declval<Lambda>()(((void)Is, any_argument{})...), void())>
: std::true_type
{};
template <typename Lambda, std::size_t N>
struct can_accept
: can_accept_impl<Lambda, std::make_index_sequence<N>>
{};
template <typename Lambda, std::size_t Max, std::size_t N, typename = void>
struct lambda_details_impl
: lambda_details_impl<Lambda, Max, N - 1>
{};
template <typename Lambda, std::size_t Max, std::size_t N>
struct lambda_details_impl<Lambda, Max, N, std::enable_if_t<can_accept<Lambda, N>::value>>
{
static constexpr bool is_variadic = (N == Max);
static constexpr std::size_t argument_count = N;
};
template <typename Lambda, std::size_t Max = 50>
struct lambda_details
: lambda_details_impl<Lambda, Max, Max>
{};
int main()
{
auto lambda0 = []() {};
auto lambda1 = [](int a) {};
auto lambda2 = [](int a, auto b) {};
auto lambda3 = [](int a, auto b, char = 'a') {};
auto lambda4 = [](int a, auto b, char = 'a', auto...) {};
std::cout << lambda_details<decltype(lambda0)>::is_variadic << " " << lambda_details<decltype(lambda0)>::argument_count << "\n"; // 0 0
std::cout << lambda_details<decltype(lambda1)>::is_variadic << " " << lambda_details<decltype(lambda1)>::argument_count << "\n"; // 0 1
std::cout << lambda_details<decltype(lambda2)>::is_variadic << " " << lambda_details<decltype(lambda2)>::argument_count << "\n"; // 0 2
std::cout << lambda_details<decltype(lambda3)>::is_variadic << " " << lambda_details<decltype(lambda3)>::argument_count << "\n"; // 0 3
std::cout << lambda_details<decltype(lambda4)>::is_variadic << " " << lambda_details<decltype(lambda4)>::argument_count << "\n"; // 1 50
}发布于 2019-01-27 16:50:19
我不知道如何计算泛型-lambda编辑的所有参数:但是yuri kilochek知道如何做到这一点:参见他的答案以获得一个很好的解决方案。
对于非通用的lambdas,如Igor所建议的,您可以检测到指向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,尝试用0调用它,并使用给定类型的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; }但这并不完美,因为这会产生假阳性和假阴性。
一个问题是,当你用“非纯变元兰博达”来检查它时
auto lambda_variadic2 = [&](std::string, auto... args){ ... };这是可变的,但第一个参数不接受int,不能检测为“纯变量”;不幸的是,下面的lambda
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; }另一个问题是被检测为“纯虚拟的”,也是非变量的泛型-lambda函数,接收的参数比选中的数目高(在示例中是50)。
并且仍然存在这样的问题,即该解决方案没有检测到lambda_variadic2 (非纯变量λ)作为变量。
下面是一个完整的编译示例,其中包含了我所能想到的关于您的问题的最好的示例
#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;
}https://stackoverflow.com/questions/54389831
复制相似问题