Вопрос

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

Это было полезно?

Решение

result_of было введен в повышении, а потом включены в TR1., и, наконец, в C ++ 0x. Следовательно 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 Гарантированное выражение, дружественное выражение, тогда как std::result_of может дать вам жесткую ошибку вместо отказа вычета. Это было исправлено в C ++ 14: std::result_of теперь требуется, чтобы быть дружественным (благодаря Эта бумага).

Так что на соответствующий компилятор C ++ 14, std::result_of_t<F(Args...)> строго превосходит. Это яснее, короче и правильно Поддерживает больше Fс.


Если, то есть вы используете его в контексте, где вы не хотите разрешать указателям членам, так 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top