使用自动说明符获取 lambda 的参数类型



我有一个元函数,它给了我一个lambda/函数的第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!");
}

带有auto说明符的第二个 lambda 无法编译,因为我的特殊化不匹配,因为auto就像一个模板参数T,这是未知的。有没有办法让这也为f2工作?

由于 lambda 是不透明的类型,除非使用模板参数类型实例化,否则模板函数没有类型,我真的不知道如何做到这一点?不可能吗?

我想你想念这个:

template <typename F>
decltype(getArgs(&F::operator())) getArgs(F);

所以最终版本将是:

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);
template <typename F>
decltype(getArgs(&F::operator())) getArgs(F);
}; // namespace details
template <typename F, std::size_t I>
using GetArg = std::tuple_element_t<I, decltype(details::getArgs(std::declval<F>()))>;

现在它编译: https://godbolt.org/z/r1PsE36Wx

有没有办法让这也为f2工作?

不,据我所知。

您可以将通用 lambda(具有一个或多个 auto 参数的 lambda(视为模板函数(包装在类中(。

排除类包装,您可以看到

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

几乎一样

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

你不能从lambda中推断出b的类型,就像你不能从foo()推断出b的类型一样:决定调用函数(从参数中推断出类型(或解释它(如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!");
// ........................................^^^

即:将 lambda 转换为函数指针。

最新更新