Во-первых, мой код компилируется и отлично работает на Mac OS X с компилятором
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1
но на Ubuntu с компилятором
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
это не скомпилируется.
У меня в шапке есть
std::vector<Obstacle::Obstacle*> obstacles;
что дает следующую ошибку компиляции в Ubuntu:
error: ‘Obstacle::Obstacle’ cannot appear in a constant-expression
Любые идеи о том, что мне нужно изменить, чтобы это работало?
Есть ли какой-нибудь волшебный флаг компиляции, который я должен использовать в Ubuntu, чтобы он работал так же, как в OS X?
Спасибо
РЕДАКТИРОВАТЬ: Obstacle
это класс.
Вы не можете передать указатель конструктора как сохраненный тип.
Вместо
std::vector<Obstacle::Obstacle*> obstacles;
пытаться
std::vector<Obstacle*> obstacles;
По-видимому Obstacle
это просто класс.
Удивительно, но также работает следующее, протестированное в g ++ 4.2, g ++ 4.3, g ++ 4.4, clang ++ 2.9 и clang ++ 3.1:
std::vector<Obstacle::Obstacle::Obstacle::Obstacle::Obstacle*> obstacles;
Несколько версий g ++ и несколько версий clang скомпилировали вышесказанное.
g ++ 4.5 и 4.6 имеют проблемы с этой конструкцией. Это похоже на ошибку g ++ версии 4.5 и выше. Так почему это должно быть законно?
Это ошибка в pre 4.5 g ++, clang и, по-видимому, других компиляторах. Соответствующая часть стандарта — 3.4.3.1, пункт 1a:
Если спецификатор вложенного имени назначает класс C, а имя, указанное после спецификатора вложенного имени, при поиске в C является именем введенного класса C (раздел 9), вместо этого считается, что имя Назовите конструктор класса C. Такое имя конструктора должно использоваться только в объявлении-идентификаторе определения конструктора, которое появляется за пределами определения класса.
Другими словами, Obstacle::Obstacle
недопустимо, за исключением случаев, когда оно используется во внешнем определении конструктора для класса Obstacle
,
Так как же эти компиляторы разбирают это? Эти компиляторы лечат Obstacle::Obstacle
как имеющий особое значение только в случае внешнего определения конструктора. Иначе, Obstacle::Obstacle
следует введенным правилам имен, но игнорирует тот факт, что это правило здесь не применяется. Obstacle::Obstacle*
не является указателем на конструктор, потому что конструкторы не имеют имен. Obstacle::Obstacle*
вместо этого означает что угодно Obstacle*
означает, когда оценивается в контексте класса Obstacle
, Но внутри класса, Obstacle*
все еще указатель на экземпляр класса Obstacle
, Obstacle::Obstacle*
это просто Obstacle*
, как есть Obstacle::Obstacle::Obstacle*
, и так далее. Куча на столько Obstacle
вы хотите, и это все еще просто Obstacle*
,