1

我正在尝试执行以下操作:

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>’

std::invoke_result的文档表明它应该可以正常工作(即没有),特别Argsvoid它说 void case 不工作是 now deprecated 的“怪癖” std::result_of

但不,void不起作用。这是有道理的,因为一个也不能做std::declval<T>()for T = void,并且std::invoke_result应该根据std::declval.

问题是,修补代码以使用 void 的最优雅/直接的方法是什么?我可以做点什么,std::conditional但我期望更好。(使用 C++17)

相关问题:这个这个

4

1 回答 1

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>>;
于 2019-01-07T13:48:01.233 回答