Если вам нужен тип чего-то, что не похоже на вызов функции, 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>()...)INVOKEdeclvaldecltypeFresult_of
Первоначально использование declval/ decltypeгарантировало дружественное к SFINAE выражение, тогда как std::result_ofмогло бы дать вам серьезную ошибку вместо ошибки вывода. Это было исправлено в C ++ 14: std::result_ofтеперь требуется, чтобы он был совместим с SFINAE (благодаря этой статье ).
Таким образом, на соответствующем компиляторе C ++ 14 std::result_of_t<F(Args...)>он строго превосходит. Это ясно, короче, и правильно † поддерживает более Fs ‡ .
† Если, то есть, вы не используете его в контексте, в котором вы не хотите разрешать указатели на члены, он
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.
decltypeуродливее, но и мощнее.result_ofможет использоваться только для вызываемых типов и требует типов в качестве аргументов. Например, вы не можете использоватьresult_ofздесь:template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );if аргументы могут быть арифметическими типами (нетFтакой функции , которую вы можете определитьF(T,U)для представленияt+u. Для пользовательских типов вы могли бы. Таким же образом (я действительно не играл с этим), я полагаю что вызовы методов-членов могут быть труднымиresult_ofбез использования связующих или лямбд