将 invoke_result 与 void 参数类型一起使用?

Use invoke_result with void argument type?

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

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 表明它应该适用于 Argsvoid(即 none),具体来说它说 void 情况不起作用是 "quirk" 现已弃用 std::result_of.

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

来实现

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

相关问题:, this.

你可以这样做:

template<typename... T>
using UnwrappedT = std::invoke_result_t<Unwrapper, T...>; 

UnwrappedT<> 会处理 void 案例。

如果你想让 UnwrappedT<void> 表示 UnwrappedT<>,你需要一些方法来删除 voidconditional 是最熟悉的做法:

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