Конструктор по умолчанию не будет компилироваться внутри класса шаблона, если включены скобки (g++4.6.1)

Я не смог найти никакой информации в Google об этом. В следующем примере:

    #include <iostream>

    class Default
    {
    public:
      void Print()
      {
        std::cout << "This is a message\n";
      }
    };

    template <class C = Default>
    class Template
    {
    public:
      static void Test()
      {
        Default oDefault();
      }
    };

    int main()
    {
      return 0;
    }

код не компилируется с ошибкой:

В статической функции-члене «static void Template::Test()»: 19:22: ошибка: аргументы шаблона по умолчанию не могут использоваться в шаблонах функций без -std=c++0x или -std=gnu++0x

Беда в том, что ему не нравятся скобки в этой строке, и я не понимаю, почему. Если я уберу скобки, код скомпилируется просто отлично. Также, если я удалю объявление шаблона (строка 13), он также отлично скомпилируется. Это ошибка или где-то есть какое-то правило, касающееся именно этой ситуации?

Я использую g++ 4.6.1 (версия gcc 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3))


person SirGuy    schedule 19.03.2012    source источник
comment
FWIW, у VC10 с этим проблем нет. (Конечно, он принимает oDefault как объявление функции, что, я согласен, является законным).   -  person MSalters    schedule 19.03.2012


Ответы (2)


Измените его на:

 Default oDefault = Default();  // Version 1

Хотя вы можете использовать:

 Default oDefault;              // Version 2

Это имеет немного другое значение.

  • Версия 1: инициализирует элементы POD нулями (в некоторых ситуациях).
  • Версия 2: приводит к тому, что элементы POD не инициализируются (в некоторых ситуациях).

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

Вы должны предпочесть нулевую инициализацию по умолчанию (в целом), как если бы класс (или любой тип членов) не имел определяемого пользователем конструктора (например, по умолчанию), тогда разница в том, что инициализация по умолчанию оставляет элементы POD неопределенными, а нулевая инициализация оставляет Элементы POD инициализированы нулем. Теперь вы можете подумать, что в моем классе нет членов, так что это не имеет значения. Но что произойдет, если вы измените класс? Вы собираетесь найти все экземпляры и обновить их; Лучше всего использовать первую версию и позволить компилятору сделать все правильно.

Для всех умопомрачительных подробностей смотрите:

Причина, по которой ваша первоначальная версия не работала, заключается в том, что на самом деле это предварительное объявление функции. Это вызвано сложным синтаксисом C++ и одним из правил, которые вам нужно запомнить. Вы можете посмотреть это как «Самый неприятный анализ».

person Martin York    schedule 19.03.2012
comment
Версия 1 вызывает инициализацию value (которая, в свою очередь, может быть определена в терминах нулевой инициализации для определенных типов). - person ildjarn; 19.03.2012
comment
@ildjarn: Да, абсолютно верно. Но я не хотел вдаваться здесь во все подробности. Конечным результатом является нулевая инициализация членов POD (что делает их четко определенными). - person Martin York; 19.03.2012
comment
Это имеет смысл (анализируя его как объявление функции), но почему наличие шаблона ‹...› перед классом вызывает ошибку? - person SirGuy; 19.03.2012
comment
Это не шаблон, скажем так. Это аргументы по умолчанию. = Default, который вызывает проблему. - person Martin York; 19.03.2012
comment
Я не знаю, почему параметр шаблона по умолчанию вызывает проблемы, но это достаточно далеко от исходной проблемы, поэтому я не буду больше об этом беспокоиться. - person SirGuy; 20.03.2012

Default oDefault();

Компилятор воспринимает это как объявление функции, а не как создание объекта.
Он объявляет функцию oDefault(), которая не принимает параметров и возвращает объект Default.

Измените его на:

Default oDefault;
person Alok Save    schedule 19.03.2012
comment
Хотя именно это предназначено, это не объясняет, почему объявление функции является недопустимым. - person MSalters; 19.03.2012