我正在尝试执行以下操作:
struct Unwrapper
{
template<typename T>
auto operator()(const T& arg, std::enable_if_t<isPrimitive<T>, void>* = nullptr) {return arg;}
template<typename T>
auto operator()(const T& arg, std::enable_if_t<!isPrimitive<T>, void>* = nullptr) {return arg.wrapped();}
void operator()(void) {}
};
template<typename T>
using UnwrappedT = std::invoke_result_t<Unwrapper, T>; // error: no type named ‘type’ in ‘struct std::invoke_result<Unwrapper, void>’
docs for std::invoke_result建议它应在Args
为void
(即无)的情况下工作,特别是说无效的情况不起作用是对已弃用的{{1 }}。
但是没有,std::result_of
不起作用。之所以说这样有道理,是因为void
也不能做std::declval<T>()
,而T = void
应该以{{1}}的方式实现。
问题是,修补代码以使其无效的最优雅/直接的方法是什么?我可以用std::invoke_result
做些什么,但我希望更好。
(使用C ++ 17)
答案 0 :(得分:1)
您可以这样做:
template<typename... T>
using UnwrappedT = std::invoke_result_t<Unwrapper, T...>;
UnwrappedT<>
将处理void
情况。
如果您希望UnwrappedT<void>
的意思是UnwrappedT<>
,则需要某种删除void
的方法。 conditional
是最熟悉的做法:
template<typename T>
using UnwrappedT = typename std::conditional_t<
std::is_void_v<T>,
std::invoke_result<Unwrapper>,
std::invoke_result<Unwrapper, T>>::type;
或者您可以在Boost.Mp11上找到一些乐趣:
template<typename T>
using UnwrappedT = mp_apply<std::invoke_result_t,
mp_remove_if<mp_list<Unwrapper, T>, std::is_void>>;