Использовать invoke_result с типом аргумента void?
Я пытаюсь сделать следующее:
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 предполагают, что это должно работать для Args
являющийся void
(то есть ни один), в частности, он говорит, что пустое дело, не работающее, было "причудой" ныне осуждаемой std::result_of
,
Но нет, void
не работает Это имеет смысл, потому что нельзя std::declval<T>()
за T = void
, а также std::invoke_result
должен быть реализован с точки зрения std::declval
,
Вопрос в том, какой самый элегантный / прямой способ исправления кода для работы с void? Я мог бы сделать что-то с std::conditional
но я ожидал лучшего.
(с использованием C++17)
2 ответа
Вы могли бы сделать это:
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>>;
Попытался ли ты ?
template<typename T>
using UnwrappedT = std::result_of_t<Unwrapper(const T&)>;