Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 计算lambda中的参数数_C++_Lambda_C++14_Template Meta Programming_Generic Lambda - Fatal编程技术网

C++ 计算lambda中的参数数

C++ 计算lambda中的参数数,c++,lambda,c++14,template-meta-programming,generic-lambda,C++,Lambda,C++14,Template Meta Programming,Generic Lambda,我需要知道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&l

我需要知道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
autolambda0=[&](){…};
自动lambda1=[&](int32_t a){…};
自动lambda2=[&](int32_t a,auto b){…};
lambda_详细信息::参数_计数;//等于0
lambda_详细信息::参数_计数;//等于1
lambda_详细信息::参数_计数;//等于2
检测可变lambda也很好,这样我也可以处理边缘情况

auto lambda_variadic = [&](auto... args){ ... };

lambda_details<decltype(lambda_variadic)>::is_variadic; // Equals true
auto lambda_variadic=[&](auto…args){…};
lambda_详细信息::是可变的;//等于真的

如何获得这些信息?

我不知道如何计算通用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()); }
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
,未被检测为“纯可变”;不幸的是,下面的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是否可以使用给定数量的此类参数调用,从任意大数开始倒数。如果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
}
#包括
#包括
#包括
构造任意参数{
模板
运算符T&()常量;
};
模板
结构可以\u接受\u impl
:std::false\u类型
{};
模板
结构可以\u接受\u impl
:std::true\u类型
{};
模板
结构可以接受吗
:可以接受吗
{};
模板
结构lambda\u详细信息\u impl
:lambda\u详细信息\u impl
{};
模板
结构lambda\u详细信息\u impl
{
静态constexpr bool是可变的=(N==最大值);
静态constexpr std::size\u t参数\u count=N;
};
模板
结构lambda_详细信息
:lambda\u详细信息\u impl
{};
int main()
{
自动lambda0=[](){};
自动lambda1=[](int a){};
自动lambda2=[](int a,auto b){};
自动lambda3=[](int a,auto b,char='a'){};
自动lambda4=[](int a,auto b,char='a',auto…{};

std::cout我已经用@yuri kilochek的答案的修改版本解决了这个问题

我们不是从50个参数开始倒计时,而是从零开始倒计时。当我们得到匹配项时,我们知道调用lambda所需的最小参数量。然后我们继续搜索,直到一个正常的最大值,以查看是否有最大参数量(当您有默认参数时,可能会发生这种情况)

如果达到参数计数限制,我们假设lambda是可变的

此实现大大减少了非可变lambda的模板实例化量。它还为所有lambda提供了最小参数量,并为任何非可变lambda提供了最大参数量

再次,非常感谢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>
{};

适用于非变量、非泛型lambda(或者通常,任何类只有一个非模板重载的
操作符()
)。首先,我不确定如何将其扩展到其他情况。请务必查看Antony Polukhin的文章。它展示了如何不仅可以推断参数的数量,还可以推断参数的类型。请接受答案。此外,您的方法会错误地将带有默认参数的lambda报告为变量。@yurikilochek呃,我忘记了默认参数-。-.我想你可以继续检查这些调用是否停止工作,但最后你会得到一个神奇的“max”请再说一遍。我必须再考虑一下。而且,在发布问题的前几天内,我不能接受我自己的答案。@yurikilochek我已经更新了我的答案,以支持默认参数。好主意,
任何参数
;我必须记住它。
#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
}
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>
{};
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
};