[C++] Разница между std :: result_of и decltype


Answers

Если вам нужен тип чего-то, что не является вызовом функции, 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>()...)); тип 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 гарантировало выражение, 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 .

Question

У меня есть некоторые проблемы с пониманием необходимости в 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 заключается в том, что для первого требуется выражение, а второе - нет?