Разница между std:: результат и decltype
у меня есть некоторые проблемы с пониманием необходимости std::result_of В C++0х. Если я правильно понял, 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 это первый нуждается в выражении, а второй нет?
2 ответов:
result_ofбыл введено в Boost, а потом входит в TR1 и, наконец, в C++0х. Поэтому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гарантированное выражение SFINAE-friendly, тогда какstd::result_ofможет дать вам жесткую ошибку вместо ошибки вычитания. Это было исправлено в C++14:std::result_ofтеперь требуется, чтобы быть SFINAE-friendly (благодаря этой статье).Итак, на соответствующем компиляторе C++14,
std::result_of_t<F(Args...)>строго начальника. Это яснее, короче, и правильно† поддерживает большеFs‡ .
†если, конечно, вы не используете его в контексте, где вы не хотите, чтобы указатели на членов, так чтоstd::result_of_tполучится в случае, когда вы хотите не получится.‡ С исключениями. Хотя он поддерживает указатели на членов,
result_ofне будет работать, если вы пытаетесь создать недопустимый type-id. Они будут включать в себя функцию, возвращающую функцию или принимающую абстрактные типы по значению. Бывший.: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.
Comments