Разница между СТД :: Result_of и decltype
Вопрос
У меня есть проблемы с пониманием необходимости std::result_of
в C ++ 0x. Если я правильно понял, result_of
используется для получения результирующего типа вызывающего объекта функционала с определенными типами параметров. Например:
template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
return f(a);
}
Я не вижу разницу со следующим кодом:
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
return f(a);
}
или
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
return f(a);
}
Единственная проблема, с которой я могу видеть с этими двумя решениями, состоит в том, что нам нужно:
- Имейте экземпляр функтора, чтобы использовать его в выражении, переданному в DECLTYPE.
- знать определенный конструктор для функтора.
Я прав думаю, что единственная разница между decltype
а также result_of
это то, что первым нуждается в выражении, тогда как вторая не делает?
Решение
result_of
было введен в повышении, а потом включены в TR1., и, наконец, в C ++ 0x. Следовательно result_of
имеет преимущество, которое обратно совместимо (с подходящей библиотекой).
decltype
Совершенно новая вещь в C ++ 0x, не ограничивает только для возврата типа функции и является языковой функцией.
Во всяком случае, на GCC 4.5, result_of
реализован с точки зрения decltype
:
template<typename _Signature>
class result_of;
template<typename _Functor, typename... _ArgTypes>
struct result_of<_Functor(_ArgTypes...)>
{
typedef
decltype( std::declval<_Functor>()(std::declval<_ArgTypes>()...) )
type;
};
Другие советы
Если вам нужен тип чего-то, что не является чем-то вроде телефонного звонка, std::result_of
просто не применяется. decltype()
может дать вам тип любого выражения.
Если мы ограничим себя только разными способами определения возврата типа функционального вызова (между std::result_of_t<F(Args...)>
а также decltype(std::declval<F>()(std::declval<Args>()...)
), то есть разница.
std::result_of<F(Args...)
определяется как:
Если выражение
INVOKE (declval<Fn>(), declval<ArgTypes>()...)
Хорошо сформирован при лечении как нерешинного операнда (пункт 5), тип Typedef участника должен назвать типdecltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
В противном случае не должно быть никакого типа участника.
Разница между result_of<F(Args..)>::type
а также decltype(std::declval<F>()(std::declval<Args>()...)
все об этом INVOKE
. Отказ С использованием declval
/decltype
непосредственно, в дополнение к тому, чтобы быть довольно дольше, чтобы ввести, только что если F
напрямую вызывается (тип объекта функции или функция или указатель функции). result_of
Кроме того, поддерживает указатели на функции членов и указателей на данные члена.
Изначально, используя declval
/decltype
Гарантированное выражение, дружественное выражение, тогда как std::result_of
может дать вам жесткую ошибку вместо отказа вычета. Это было исправлено в C ++ 14: std::result_of
теперь требуется, чтобы быть дружественным (благодаря Эта бумага).
Так что на соответствующий компилятор C ++ 14, std::result_of_t<F(Args...)>
строго превосходит. Это яснее, короче и правильно† Поддерживает больше F
с‡ .
†Если, то есть вы используете его в контексте, где вы не хотите разрешать указателям членам, так
std :: result_of_t.
будет преуспеть в случае, если вы можете захотеть, чтобы это не удалось.
‡ С исключениями. Хотя он поддерживает указатели членам, result_of
не будет работать, если вы попытаетесь создать недействительный Тип идентификатора. Отказ Они будут включать функцию, возвращающую функцию или принимающую абстрактные типы по значению. Бывший.:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
Правильное использование было бы result_of_t<F&()>
, но это деталь, с которыми вам не нужно помнить decltype
.