我有一个元函数,它给了我一个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 转换为函数指针。