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()
случай, но в остальном - это приблизительный путь.