[英]C++17: Wrapping callable using generic variadic lambda
我想在另一个callable中透明地包装任何类型的可调用(例如lambda)以注入其他功能。 包装器的类型应该与原始可调用的类型相同:
我试图使用泛型variadic lambdas作为包装:
#include <iostream>
#include <type_traits>
template<class TCallable>
auto wrap(TCallable&& callable) {
return [callable = std::forward<TCallable>(callable)](auto&&... args) -> std::invoke_result_t<TCallable,decltype(args)...> {
std::cout << "This is some additional functionality" << std::endl;
return callable(std::forward<decltype(args)>(args)...);
};
}
int main(int argc, char *argv[])
{
auto callable1 = []() {
std::cout << "test1" << std::endl;
};
auto callable2 = [](int arg) {
std::cout << "test2: " << arg << std::endl;
};
auto wrapped1 = wrap(callable1);
auto wrapped2 = wrap(callable2);
static_assert(std::is_invocable_v<decltype(callable1)>); // OK
static_assert(std::is_invocable_v<decltype(wrapped1)>); // fails
static_assert(std::is_invocable_v<decltype(callable2), int>); // OK
static_assert(std::is_invocable_v<decltype(wrapped2), int>); // fails
}
正如static_assert
上的注释所示,包装器callables的调用方式与原始callable的调用方式不同。 需要改变什么才能实现所需的功能?
给出的示例是使用Visual Studio 2017(msvc 15.9.0)编译的。
这可能是MSVC实现std::invoke_result
或std::is_invocable
一个错误(即使使用Visual Studio 15.9.2,我也可以在这里重现这个问题)。 你的代码使用clang(libc ++)和gcc工作正常,我没有看到任何理由不应该这样做。 但是,你真的不需要std::invoke_result
,你可以让你的lambda推导出返回类型:
template<class TCallable>
auto wrap(TCallable&& callable) {
return [callable = std::forward<TCallable>(callable)](auto&&... args) -> decltype(auto) {
std::cout << "This is some additional functionality" << std::endl;
return callable(std::forward<decltype(args)>(args)...);
};
}
那么MSVC似乎也能正常工作 ......
编辑:正如Piotr Skotnicki在下面的评论中所指出的, decltype(auto)
将禁止SFINAE 。 要解决此问题,您可以使用尾随返回类型:
template<class TCallable>
auto wrap(TCallable&& callable) {
return [callable = std::forward<TCallable>(callable)](auto&&... args) -> decltype(callable(std::forward<decltype(args)>(args)...)) {
std::cout << "This is some additional functionality" << std::endl;
return callable(std::forward<decltype(args)>(args)...);
};
}
这将是一个更多的打字,但应该与SFINAE一起使用, 并且似乎也可以与MSVC一起使用 ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.