G++ при использовании необязательного ключевого слова 'struct'

Если я напишу эту программу:

#include <iostream>

namespace foo {
    struct bar {
        int x;
    };
}

int main (void) {
    struct foo::bar *a = new struct foo::bar;
    delete a;
    return 0;
}

и скомпилируйте его с помощью:

g++ main.cxx -Wall -Wextra

Он дает мне это предупреждение:

main.cxx: In function ‘int main()’:
main.cxx:10:39: warning: declaration ‘struct foo::bar’ does not declare anything [enabled by default]

Однако, если я вывожу ключевое слово struct после ключевого слова new:

#include <iostream>

namespace foo {
    struct bar {
        int x;
    };
}

int main (void) {
    struct foo::bar *a = new foo::bar;
    delete a;
    return 0;
}

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

Ответ 1

В С++ ключевое слово struct определяет тип, а новому типу больше не требуется ключевое слово struct. Это одно из многих различий между C и С++.

Ответ 2

Изучение ошибки:

main.cxx: 10: 39: warning: Объявление ‘struct foo::bar’ не объявляет ничего [включено по умолчанию]

g++ думает, что вы объявляете новый struct с именем foo::bar вместо выделения памяти типа struct foo::bar. Мое предположение было бы потому, что g++ предполагает любое использование struct, которое не объявляет lvalue, с целью объявления типа.

Ответ 3

Просто опубликуйте минимальный код, который делает и не иллюстрирует проблему:

namespace N {
struct A {};
}

struct B {};

int main() {
    struct N::A * a  = new struct N::A; // problem
    struct B * b  = new struct B;       // ok
}

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

Ответ 4

Примечание:

   struct foo::bar *a = new struct foo::bar;
// ^^^^^^ (1)
                        //  ^^^^^^ (2)
  • Не требуется в С++
    • Помещение структуры здесь - похмелье от C и больше не нужно в С++
      Поскольку все типы находятся в одном и том же namespace.
      В то время как в C-структурах было собственное пространство имен отдельно от других типов.
      Допускается сохранение обратной совместимости с C.
  • struct выглядит так, как будто она объявляет что-то.

В С++ выше указано как:

   foo::bar* a = new foo::bar;

//или предпочтительно

   foo::bar* a = new foo::bar(); // This makes a difference if you don't define
                                 // a default constructor.

От Давида (ниже)

Важно, я думаю, что это должно быть в ответе, а не в комментариях:

namespace foo
{
    struct bar {};
    void bar() {}
}

int main()
{
    struct foo::bar* p = new struct foo::bar;
    // Needed here because the compiler can't tell the difference between
    // a struct and a function otherwise
}