Ответ 1
Поскольку любой полученный результат зависит от параметра шаблона, необходимо typedef typename
.
decltype
- стандартная функция С++ 11. Это "оператор", который принимает выражение и возвращает тип.
typedef typename decltype( T().toCPD() ) D; // can't use T:: as it nonstatic
Если T()
не является допустимым (T
не является конструктивным по умолчанию), вы захотите declval
, который является функцией, которая принимает тип и возвращает бессмысленное недопустимое значение этого типа. declval
может использоваться только в неоцененных контекстах, таких как decltype
.
typedef typename decltype( std::declval<T>().toCPD() ) D;
До того, как С++ 11, decltype
был нестандартным расширением компилятором Microsoft MSVC. Его поведение, возможно, слегка изменилось стандартизацией.
typeof
является расширением GCC эквивалентного pre-С++ 11, например decltype
, который также был клонирован в других компиляторах. Здесь представлена его документация от GCC. Эта страница не дает никакого сравнения между функциями, но отмечает, что typeof
должен быть вызван __typeof__
при использовании стандартного режима (-std=c++YY
, который вы должны всегда делать), и он доступен в C, а также С++.
Для обеспечения совместимости C __typeof__
не будет разрешать ссылочный тип из выражения glvalue. Таким образом, он действительно подходит только для C. Вероятно, это объясняет, почему функция С++ не наследовала более понятного имени: GNU не желала жертвовать обратной совместимостью, тогда как Microsoft меньше заботится о C и, возможно, нуждается в меньшем количестве изменений.
result_of
является метафоном С++ 11 (ранее стандартизованным в библиотеке ISO TR1 с 2006 года). Это шаблон, который принимает вызываемый тип (например, функцию int(void)
, указатель функции int(*)(void)
, класс functor, реализующий operator()
, или указатель-на-член-функцию &T::toCPD
)) и тип-список аргументов для этот тип и предоставляет тип возврата, если вызов будет работать.
Чтобы использовать result_of
с указателем на функцию-член, вы должны включить родительский тип объекта в список аргументов в качестве суррогата для this
.
typedef typename std::result_of< decltype( & T::toCPD ) ( T * ) >::type D;
Это очень хрупкое, хотя, поскольку &T::toCPD
не может быть разрешено, если есть перегрузка, например, неконстантная версия. Это верно, несмотря на то, что T *
или T const *
должно быть явно выписано! В большинстве случаев вам лучше с decltype
и declval
.