Получить тип аргумента лямбда с автоопределителем - PullRequest
2 голосов
/ 12 апреля 2019

У меня есть мета-функция, которая дает мне тип I -ого аргумента лямбда / функции:

#include <iostream>
#include <tuple>

namespace details
{
    //! Spezialization for Funktion-Pointers
    template<typename Ret, typename... Args>
    std::tuple<Args...> getArgs(Ret (*)(Args...));

    //! Spezialization for Functor/Lambdas
    template<typename F, typename Ret, typename... Args>
    std::tuple<Args...> getArgs(Ret (F::*)(Args...));

    //! Spezialization for Functor/Lambdas
    template<typename F, typename Ret, typename... Args>
    std::tuple<Args...> getArgs(Ret (F::*)(Args...) const);

}; // namespace details

template<typename F, std::size_t I>
using GetArg = std::tuple_element_t<I, decltype(details::getArgs(std::declval<F>()))>;

int main()
{
    auto f1 = [](int a, int b){};
    static_assert(std::is_same<GetArg<decltype(f1), 0>, int>{}, "Not the same!");

    // auto f2 = [](int a, auto b){};
    // static_assert(std::is_same<GetArg<decltype(f2), 0>, int>{}, "Not the same!");
}

Live

вторая лямбда со спецификатором auto не компилируется, поскольку мои специализации не совпадают, потому что auto подобен параметру шаблона T, который неизвестен.Есть ли способ сделать эту работу также для f2?

Поскольку лямбда является непрозрачным типом, а функция шаблона не имеет типа, если не создан экземпляр с типами аргументов шаблона, я не имею ни малейшего представления о том, как заставить это работать?Это невозможно?

1 Ответ

0 голосов
/ 12 апреля 2019

Есть ли способ сделать эту работу также для f2?

Нет, насколько я знаю.

Вы можете увидеть общую лямбду (лямбду с одним или несколькими auto аргументами) почти как функцию шаблона (обернутую в класс).

За исключением переноса класса, вы можете видеть

[](int a, auto b){};

почти как

template <typename T>
void foo (int a, T b)
 { };

Вы не можете вывести тип b из лямбдыточно так же, как вы не можете вывести тип b из foo(): решено вызвать функцию (вывести тип из аргумента) или объяснить ее (что-то вроде foo<int>).

Но есливы просто пишете decltype(foo), компилятор не может решить, какой тип T, поэтому выдает ошибку.

В любом случае, я получаю ошибку, также компилируя

static_assert(std::is_same<GetArg<decltype(f1), 0>, int>{}, "Not the same!");

Полагаю, вынужно написать GetArg следующим образом

using GetArg = std::tuple_element_t<I, decltype(details::getArgs(&F::operator()))>;
// ..............................................................^^^^^^^^^^^^^^

Или вы можете сохранить свой фактический GetArg, но вызывая его с помощью +f1

static_assert(std::is_same<GetArg<decltype(+f1), 0>, int>{}, "Not the same!");
// ........................................^^^

, то есть: преобразовать лямбду вуказатель на функцию.

...