Подтвердить что ты не робот

Странное неинициализированное поведение члена-константы

Рассмотрим этот фрагмент кода:

struct Foo {

};

template<typename T>
struct Bar {
    const T foo;
};

int main() {
    Bar<Foo> test;
}

Я компилирую его с g++ - 4.9.2 с [-std = С++ 11 -O0 -g3 -pedantic -Wall -Wextra -Wconversion] и получая error: uninitialized const member in ‘struct Bar<Foo>’. Это довольно очевидно.

НО попробуйте просто добавить std::string в качестве компилятора Foo и программы!

#include <string>
struct Foo {
    std::string test;
};
// (...)

Что происходит? Замена типа теста на двойную причину не позволяет скомпилировать программу. Какой член строки изменяется в классе?

Ссылка на онлайн-компилятор с этим фрагментом.

Кажется, что gcc ведет себя так же, как и версия 4.6.

4b9b3361

Ответ 1

Я думаю, что он должен постоянно вызывать ошибку. Кланг делает это. Стандарт С++ говорит в пункте (4.3) раздела 12.1.4, что конструктор по умолчанию неявно удаляется, когда

- любой невариантный нестатический элемент данных типа const-qual (или его массив), не имеющего привязки или равного инициализатора, не имеет предоставленный пользователем конструктор по умолчанию,

Поскольку Foo не имеет предоставленного пользователем конструктора по умолчанию, Bar должен иметь неявно удаленный конструктор по умолчанию, и поэтому создание Bar<Foo> test в main должно приводить к ошибке.

Может быть, сообщить об ошибке в GCC?

Ответ 2

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

В обоих случаях должна быть ошибка.

Ответ 3

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

struct Foo {
    std::string test;
    Foo():test() {;}
};

template<typename T>
struct Bar {
    const T foo;
    Bar(): foo() {;}
};

int main() {
    Bar<Foo> test;
}

который компилируется как с clang, так и с MSVC.

(но я должен признать, что я до сих пор не нашел ссылку в gcc doc, объясняющую это...)