Если вам нужен тип чего-то, что не похоже на вызов функции, 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
гарантировало дружественное к SFINAE выражение, тогда как std::result_of
могло бы дать вам серьезную ошибку вместо ошибки вывода. Это было исправлено в C ++ 14: std::result_of
теперь требуется, чтобы он был совместим с SFINAE (благодаря этой статье ).
Таким образом, на соответствующем компиляторе C ++ 14 std::result_of_t<F(Args...)>
он строго превосходит. Это ясно, короче, и правильно † поддерживает более F
s ‡ .
† Если, то есть, вы не используете его в контексте, в котором вы не хотите разрешать указатели на члены, он
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
без использования связующих или лямбд