Разница между 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 это первый нуждается в выражении, а второй нет?

609   2  

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

    Ничего не найдено.