Анонимная структура в typedef класса черты - PullRequest
14 голосов
/ 09 мая 2011

Извините за смешной заголовок.

До C ++ 0x есть ограничения в использовании функционально-локальных структур («локальных типов») в качестве аргументов шаблона.Мой вопрос по существу, если подобные ограничения применяются к анонимным структурам.В частности, в контексте класса признаков:

template <typename T>
struct trait;

template <>
struct trait<int> {
    typedef int type;
};

template <typename T>
struct trait<std::basic_string<T> > {
    typedef struct {
        T value;
    } type;
};

trait<std::string>::type foo; // Is this valid?

template <typename T>
void f() { }

f<trait<std::string>::type> >(); // Is this?

template <typename T>
void g() { f<typename trait<T>::type>(); }

g<std::string>(); // And this?

Является ли это действительным и надежным?Он компилируется в последних версиях GCC и LLVM, но я все еще не уверен, является ли это строго допустимым, и понимают ли это VC ++ и ICC.

Ответы [ 4 ]

6 голосов
/ 09 мая 2011

Для справки цитата из связанного вопроса в 14.3.1 / 2:

Локальный тип, тип без связи, безымянный тип или составной тип от любого из этих типов не должно быть используется в качестве аргумента шаблона для параметр типа шаблона.

Моя интерпретация заключается в том, что typedef struct создает псевдоним для безымянного типа и, таким образом, его нельзя использовать в качестве параметра типа шаблона. Также отметим, что дополнительно в C typedef struct {} Foo; трактуется несколько иначе, чем в struct Foo {};, что дает прецедент того, что эти две формы не эквивалентны (хотя, по общему признанию, в C ++ разницы нет).

Таким образом, может показаться, что ваш первый пример работает (поскольку он не использует безымянный тип в качестве параметра типа шаблона), тогда как второй и третий примеры будут технически недопустимыми (поскольку они используют его как параметр типа шаблона).

Наконец, в заключение я должен спросить, есть ли причина, по которой вы не можете назвать структуру вместо typedef ее?

РЕДАКТИРОВАТЬ: от 7.1.3 / 1:

... Таким образом, typedef-name является синонимом другой тип. Typedef-имя не ввести новый тип, как класс декларация (9.1) или перечисление enum делает ...

Это строго подразумевает, что использование typedef таким способом не вводит тип, подходящий для использования в качестве параметра типа шаблона.

4 голосов
/ 09 мая 2011

В следующем стандарте это ограничение снято с языка.Стандарт гласит:

14.3.1 [temp.arg.type] / 1

Аргумент шаблона для параметра шаблона, который является типом, должен быть идентификатором типа.

И typedef является допустимым type-id .На самом деле следующий абзац содержит такой пример:

14.3.1 [temp.arg.type] / 2

template <class T> class X { };
template <class T> void f(T t) { }
void f() { 
   typedef struct { } B;
   B b;
   X<B> x3;
   f(b);
}

(где я обрезал большинство других примеров) В примере показано, что безымянный тип может использоваться в качестве аргумента шаблона класса как в шаблонах классов, так и в шаблонах функций.

3 голосов
/ 10 мая 2011

Объявление typedef, которое определяет анонимный класс и typedef-имя для этого класса, typedef-name является именем класса для целей связывания.Поэтому допустимо использовать этот класс в качестве параметра шаблона, если он соответствует другим критериям.

См. 7.1.3p5 стандарта C ++ 03

Если объявление typedef определяетбезымянный класс (или enum), первое имя typedef, объявленное объявлением как этот тип класса (или тип enum), используется для обозначения типа класса (или типа enum) только для целей связывания (3.5).[Пример:

typedef struct { } *ps, S; // S is the class name for linkage purposes

Это 7.1.3p9 в C ++ 0x FDIS.

FWIW, этот код компилируется нормально с MSVC2010 (по модулю опечаток).

0 голосов
/ 09 мая 2011

Ну, это эквивалентно

template <typename T>
struct trait<std::basic_string<T> > {
    struct type {
        T value;
    };
};

что вполне законно.

...