C++11: std::result_of<> аргумент шаблона vs std::function<>

Я сделал некоторые исследования std::result_of<>и я знаю, как это используется на высоком уровне, но я все еще довольно запутался в этой волшебной вещи.

Так что, если я правильно понимаю, форма R (Args..) должен интерпретироваться компилятором как тип функции, принимающий аргументы типов Args... и возвращающий тип Rи использование очень оправдано при указании std::function<int(int)>, который объявляет тип функции, принимающей int в качестве единственного аргумента и возвращения int,

Однако значение вышеизложенного внезапно меняется, когда то же самое понятие используется в контексте std::result_of<F(Args...)> (обратите внимание, что я изменился R в Fи удалил (пространство) между F а также ( чтобы обозначить разницу - в соответствии с смыслом F(Args...) становится временем компиляции INVOKE выражение - я имею в виду, я вроде понимаю, что основная цель std::result_of<F(Args...)> это использовать понятие INVOKE выбрать правильную перегрузку (если имеется более одной перегрузки) и, конечно, вывести тип возврата такого вызова (во время разрешения времени компиляции) - это будет примерно похоже на: decltype(std::declval<F>()(std::declval<Args>()...)) - однако понятие F (Args...) - по сравнению с std::function<R (Args...)> case - был бы интерпретирован компилятором как принимающий тип функции Args... и возвращая тип F, где сейчас F это тип функции, который мы пытаемся получить тип возвращаемого значения!

Конечно, с помощью decltype а также std::declval, реализация std::result_of кажется разумным, но я читал, что boost как-то реализован result_of в C++98/03 где decltype а также std::declval не было - мне интересно, как это было бы возможно (возможно, с некоторыми очень хакерскими трюками)?

Итак, чтобы повторить: это понятие R (Args...) в контексте того, что аргумент шаблона всегда интерпретируется / выводится как тип функции с возвращаемым типом Rнезависимо от того, является ли вмещающий шаблон std::function<> или же std::result_of<>? в то время как std::result_of<> каким-то образом делает некоторую реинтерпретацию "возвращаемого типа" Fи "возвращает" фактический тип возвращаемого значения, определенный std::result_of<F(Args...)>::type? Или же std::result_of<F(Args...)> просто интерпретирует F(Args...) по-другому, поэтому он знает, что это волшебное INVOKE выражение?

Спасибо за ваши предстоящие разъяснения!

2 ответа

Z(A,B,C) это просто тип. Это тип функции.

Вы можете передавать типы в шаблоны. То, что шаблон делает с типом, зависит от шаблона.

std::function<X> ожидает тип функции. Он превращает его в подпись его operator(),

std::result_of<X> ожидает тип функции. Если дано A(Ts...), он рассчитывает результат использования () называть объект типа A с аргументами Ts...,

Он был помечен как ограниченный в C++17, потому что типы функций иногда делают забавные вещи (аргументы распада, strip const и т. Д.) Есть сейчас invoke_result<F, Ts...> который ведет себя так же, как result_of<F(Ts...)> с несколькими угловыми отличиями.

Результатом всегда было злоупотребление синтаксисом типа функции. Но здесь нет глубокой магии; шаблоны делают все, что хотят с типами, переданными в.

В C++03 вы можете получить ограниченную функциональность, подобную "result_of", путем сопоставления с типом указателя на тип функции и изучения &T::operator(), Невозможно получить все необходимые возможности в C++03 без decltype/declval, расширений компилятора или заголовков TR pre- C++11.

Чтобы реализовать это без decltype- ну, простая реализация старой школы, которая охватывает несколько основных случаев, вероятно, будет что-то вроде

template<class F> struct MemberRetVal;
template<class C,typename R> struct MemberRetVal<R (C::*)()> {
    using type = R;
};
template<class C,typename R> struct MemberRetVal<R (C::*)() const> {
    using type = R;
};
template<class C,typename R, typename A1> struct MemberRetVal<R (C::*)(A1)> {
    using type = R;
};
template<class C,typename R, typename A1> struct MemberRetVal<R (C::*)(A1) const> {
    using type = R;
};
// ...
// A few more member function arities
// ...

template<typename F> struct ResultOf;
template<typename F> struct ResultOf<F (*)()> {
    using type = typename MemberRetVal<&F::operator()>::type;
};
template<typename R> struct ResultOf<(R (*)())(*)()> {
    using type = R;
};
template<typename F, typename A1> struct ResultOf<F (*)(A1)> {
    using type = typename MemberRetVal<&F::operator()>::type;
};
template<typename R, typename A1> struct ResultOf<(R (*)(A1))(*)(A1)> {
    using type = R;
};
// and so forth

Несколько более сложная отправка требуется для operator() случай, но в остальном - это приблизительный путь.

Другие вопросы по тегам