Могут ли имена typedef использоваться для объявления или определения конструкторов?
Standardese:
[class.ctor] 12.1/1 говорит
Для объявления или определения конструктора используется специальный синтаксис декларатора. Синтаксис использует:
- необязательный spec-specifier-seq, в котором каждый спецификатор-спецификатор является либо спецификатором функции, либо constexpr,
- имя класса конструкторов и
- список параметров
в этом порядке.
[class.name] 9.1/4 говорит
Имя typedef-name (7.1.3), которое называет тип класса или cv-квалификацию его версия также является именем класса. Если имя typedef, которое Тип класса cv-qual используется, когда требуется имя класса, cv-квалификаторы игнорируются. Имя typedef не должно использоваться как идентификатор в заголовке класса.
Также [expr.prim.general] 5.1.1/8 говорит
В тех случаях, когда используется имя класса:: class-name, а также имена двух классов к тому же классу, это обозначение называет конструктор (12.1).
Применение:
Мне кажется, что объявление конструктора должно быть разрешено с использованием имен typedef (несмотря на то, что 12.1/1 не использует курсивом имя класса).
Например, данный:
struct Foo;
typedef Foo Bar;
затем
struct Foo { Bar() {} }; // defines Foo constructor. - 1
или вместо этого
struct Foo;
struct Foo { Foo() };
typedef Foo Bar;
затем
Foo::Bar() {}; // defines Foo constructor - 2
или
Bar::Bar() {}; // defines Foo constructor - 3
или
Bar::Foo() {}; // defines Foo constructor - 4
Любое из них должно быть законным. Однако никто, кажется, не принимает определения 2 или 3, MSVC принимает 1, а MSVC, clang и gcc все принимают 4.
Правильно ли мой анализ, и все эти компиляторы ошибочны?
Ответы
Ответ 1
§12.1/3 рабочий проект N3337 (февраль 2012 г.) гласит
Имя typedef не должно использоваться как имя класса в объявлении-id для объявления конструктора.
Это исключает (1).
В §12.1/1, по-видимому, используется термин "декларация" для обеих деклараций и определений:
Для объявления или определения конструктора используется специальный синтаксис декларатора. [...] В таком заявлении [...]
(без прямого упоминания "определений" ). Я думаю, что это немного неясно, относится ли это к определениям вне класса или только к встроенным определениям. Если это относится ко всем видам определений, это также исключает (2) и (3). (4) должно быть законным в любом случае.
Ответ 2
К сожалению, это работает в Microsoft C, но не в других компиляторах, которые я использую. Особенно когда желательно в шаблонах. Может быть, я не знаю "совместимого со стандартами способа", но это действительно полезно в шаблонах.
template<class T, class T1, ... /* messy, verbose */ >
class MyTemplate {
protected:
typedef MyTemplate<T,T1, ... /* messy, verbose */ > SimplerName;
// declare a constructor
SimplerName(int arg) { ... }
};
class SubClass
: public MyTemplate<x,y....>
{
public:
SubClass(int arg) : SimplerName(arg) { ... }
}.
Может быть, другой вопрос, возможно, это не работает в GCC, Clang и т.д. Есть ли способ сделать это в этих других компиляторах?