Я не знаю, как подсчитать все аргументы обобщённой лямбды [ edit : но Юрий Килочек знает, как это сделать: см. Его ответ для отличного решения].
Для неуниверсальных лямбд, как предложил Игорь Тандетник, вы можете определить типы (возврат и аргументы) указателя на 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_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; }
, но это не идеально, потому что дает ложные срабатывания и ложные отрицания.
Проблема в том, что при проверке с помощью«не чистая вариадическая лямбда» как
auto lambda_variadic2 = [&](std::string, auto... args){ ... };
, который является переменным, но первый аргумент не принимает int
, не определяется как «чистый переменный»;к сожалению, следующая лямбда
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; }
Другая проблема заключается в том, что обнаруживаются как «чисто виртуальные», а также не вариационные функции generic-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;
}