Decltype, result_of или typeof?

У меня есть:

class A {
public:
    B           toCPD() const;

и

template<typename T>
class Ev {
public:
    typedef result_of(T::toCPD()) D;

После создания экземпляра Ev<A> компилятор говорит:

meta.h: 12: ошибка: "T:: toCPD" не является типом

ни decltype, ни typeof не работают.

Ответ 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.

Ответ 2

result_of не является функцией ни оператора. result_of - это мета-функция, имеющая функцию как параметр шаблон и устанавливающий тип результата в типе члена

typedef typename result_of<T::toCPD()>::type D;