【发布时间】:2017-05-09 17:26:21
【问题描述】:
我希望能够在编译时确定,给定一个通用 lambda 类型,是否可以使用给定的一组参数类型来调用它。我有以下示例 C++14 实现:
#include <iostream>
// helper function; this overload handles the case that the call is possible
// use SFINAE with the extra template parameter to remove this from consideration when the
// call is ill-formed
template <typename Func, typename... Args, typename = decltype(std::declval<Func>()(std::declval<Args>()...))>
auto eval(Func f, Args &&... args) { return f(args...); }
// special type returned from `eval()` when the call can't be done
struct invalid_call { };
// helper function; this overload handles the case that the call is not possible
template <typename Func>
invalid_call eval(Func f, ...) { return invalid_call{}; };
// bring in std::negation from C++17 to help create the below trait
template<class B>
struct negation : std::integral_constant<bool, !bool(B::value)> { };
// trait that determines whether `Func` can be invoked with an argument list of types `Args...`
template <typename Func, typename... Args>
using can_call = negation<std::is_same<decltype(eval(std::declval<Func>(), std::declval<Args>()...)), invalid_call>>;
// arbitary type that has no `operator+`
struct foo {};
int main()
{
auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };
using FuncType = decltype(func);
std::cout << "can call with (int, int): " << can_call<FuncType, int, int>::value << std::endl;
std::cout << "can call with (foo, foo): " << can_call<FuncType, foo, foo>::value << std::endl;
}
这个例子可以正常工作。我不喜欢的是必须声明 lambda 的繁琐方式:
auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };
即必须指定尾随返回类型,因为C++14's deduced return types don't work with SFINAE。返回类型推导需要将参数列表类型替换为可调用的模板调用运算符,并且如果那里发生错误,则程序是非良构的。
理想情况下,我可以做到以下几点:
auto func = [](auto a1, auto a2) { return a1 + a2; };
并让返回类型自动运行;这将是提供给我的用户的最直观的界面。这是一个非常简单的示例,因此decltype() 的参数看起来不错,但实际上,lambda 可能是多个语句,这不适用于这种方法。所以我的问题是:
使用任何现代 C++ 技术(C++14 最好,但如果需要,我也愿意接受更新的功能),有什么方法可以在编译时测试通用 lambda 是否可以调用参数类型的任意列表?
【问题讨论】:
-
似乎你的问题中有你的问题的答案:不,不是没有尾随返回类型。
-
@Barry:我认为可能是这样,但我的现代 C++ 知识并不权威,所以我想看看是否还有其他技巧。如果我受限于对尾随返回类型的需求,那么这种方法的用处就会大大降低,因为 lambda 不能有多个语句。
-
由于返回类型推导需要您的 lambda 在每次推导时推导相同的返回类型,您可以只使用第一个返回语句(或最简单的)作为尾随返回类型 decltype。这不是真正的解决方案,但它减少了问题空间。
标签: c++ lambda c++14 template-meta-programming