从这个问题(Is it possible to figure out the parameter type and return type of a lambda?)开始,我经常使用建议的function_traits
。然而,随着C ++ 14的多态性lambda已经到来,他们给了我一个艰难的时间。
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
enum { arity = sizeof...(Args) };
// arity is the number of arguments.
typedef ReturnType result_type;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
// the i-th argument is equivalent to the i-th tuple element of a tuple
// composed of those arguments.
};
};
另一个问题答案中提出的operator()
现已超载,正如标准中所述,以支持:
auto lambda1 = [](auto& a) { a.foo(); }
和
auto lambda2 = [](auto&&... args) { foo(args...); };
此重载现在将function_traits
类分开,因为编译器无法解析operator()
的正确版本。
lambda.cpp:98:38: error: reference to overloaded function could not be
resolved; did you mean to call it?
typedef function_traits<decltype(&T::operator())> caller;
用C ++ 14在多态lambda上实现function_traits
的功能是否可行?
答案 0 :(得分:1)
目前在一般意义上这是不可能做到的,但是如果你的lambdas对所有参数都有auto并且可以使用某些已知类型替换它们,那么你可以修改这个问题的答案: C++ metafunction to determine whether a type is callable
沿着
的路线static const bool OneArg = (sizeof( test<T, int>(0) ) == 1);
static const bool TwoArg = (sizeof( test<T, int, int>(0) ) == 1);
static const bool ThreeArg = (sizeof( test<T, int, int, int>(0) ) == 1);
static constexpr std::size_t TemplatedOperatorArgSize =
OneArg
? 1
: TwoArg
? 2
: ThreeArg
? 3
: -1;
为嵌套三元组道歉。然后用这样的东西来称呼它:
template<size_t N, typename T>
struct Apply {
template<typename F, typename... A>
static inline decltype(auto) apply(F && f, A &&... a) {
return Apply<N-1, T>::apply(::std::forward<F>(f), std::declval<T>(), ::std::forward<A>(a)...);
}
};
template<typename T>
struct Apply<0, T> {
template<typename F, typename... A>
static inline decltype(auto) apply(F && f, A &&... a) {
return invoke(std::forward<F>(f), std::forward<A>(a)...);
}
};
template<std::size_t Size, typename T, typename F>
inline decltype(auto) apply(F && f) {
return Apply<Size, T>::apply(::std::forward<F>(f));
}
使用来自http://en.cppreference.com/w/cpp/utility/functional/invoke
的调用获取返回类型
using return_type = decltype(
apply<has_callable_operator<T>::TemplatedOperatorArgSize, int>(function)
);
可以使用std::make_index_sequence
但一般来说,我说你要去兔子洞了。祝你好运。
注意:没有测试应用代码,但它应该足以让你去。
编辑:此外,返回类型需要独立于参数类型才能实现您想要的效果
答案 1 :(得分:1)
在使用 获取功能 实施 缓存 时,我遇到了类似的情况。 类似的东西:
template<class KEY, class VALUE, class FetchFunctor>
class Cache { ... };
我想保存用户需要说明他/她 FetchFunctor 的类型,而没有C++17 class template argument deduction我去了 < em> createCahce 这样的辅助方法:
// [1]
template<class KEY, class VALUE, class FetchFunctor>
auto createCache(FetchFunctor fetchFunctor) {
return Cache<KEY, VALUE, FetchFunctor>(fetchFunctor);
}
因此,创建缓存非常容易,例如:
auto cache = createCache<int, int>([](int i){return i+3;});
允许用户创建缓存而不需要提供 密钥 和 值 类型的缓存,并从提供的 FetchFunctor 中推断出它们。所以我添加了一个额外的 createCache 方法:
// [2]
template<class FetchFunctor>
auto createCache(FetchFunctor fetchFunctor) {
// function_traits is a namespace where I 'hide' the
// traits structs for result type and arguments type deduction
using f = function_traits::traits<decltype(fetchFunctor)>;
using KEY = typename f::template arg<0>::type;
using VALUE = typename f::result_type;
return Cache<KEY, VALUE, FetchFunctor>(fetchFunctor);
}
现在创建缓存更加容易:
auto cache = createCache([](int i){return i+3;});
幸运的是。
这样我们就可以支持以下所有情况:
// [a]
auto cache = createCache([](int i){return i+3;});
// compiler deduces Key, Value to be: int, int - using the 2nd createCache
// [b]
auto cache = createCache<int, int>([](auto i){return i+3;});
// we have a generic lambda so we provide Key and Value - using the 1st createCache
// [c]
auto cache = createCache<string, string>(
[](const char* s){return string(s) + '!';}
);
// we want different Key and/or Value than would be deduced - we use 1st createCache
以下内容无法编译:
auto cache = createCache([](auto i){return i+3;});
// we cannot deduce types for generic lambda
// compiler goes to the 2nd createCache but Key and Value cannot be deduced
// - compilation error
但这不应该打扰我们......你可以提供上面[b]中的键和值。