Есть несколько вопросов о переполнении стека по строкам «почему я не могу инициализировать статические члены данных в классе на C++». Большинство ответов цитируют со стандартного сообщения, указывающего вам , что вы можете сделать; те, которые пытаются ответить , почему обычно указывают на ссылку (теперь, казалось бы, недоступную) [EDIT: на самом деле это доступно, см. ниже] на сайте Stroustrup, где он утверждает, что разрешение инициализации статических элементов в классе нарушало бы правило одного определения (УСО).Почему внутриклассическая инициализация статических членов нарушает ODR?
Однако эти ответы кажутся чрезмерно упрощенными. Компилятор отлично справляется с проблемами ODR, когда захочет. Например, рассмотрим следующее в заголовке C++:
struct SimpleExample
{
static const std::string str;
};
// This must appear in exactly one TU, not a header, or else violate the ODR
// const std::string SimpleExample::str = "String 1";
template <int I>
struct TemplateExample
{
static const std::string str;
};
// But this is fine in a header
template <int I>
const std::string TemplateExample<I>::str = "String 2";
Если я создаю экземпляр TemplateExample<0>
в нескольких единицах трансляции, компилятор/компоновщик волшебные пинки в и я получаю ровно одну копию TemplateExample<0>::str
в окончательном исполняемого файла.
Итак, мой вопрос заключается в том, что, возможно, компилятор, возможно, решил проблему ODR для статических членов классов шаблонов, почему он не может это сделать и для классов без шаблонов?
EDIT: Ответ на вопросник Stroustrup доступен here. Соответствующее предложение:
Однако, чтобы избежать сложных правил компоновщика, C++ требует, чтобы каждый объект имел уникальное определение. Это правило будет нарушено, если C++ допускает определение класса объектов в классе, которое необходимо сохранить в памяти как объекты
Похоже, что эти «сложные правила компоновщика» существуют и используются в случае шаблона, поэтому почему бы и в простом случае?
C++ 11 расслабляет это ограничение. Вы можете выполнить инициализацию в классе с помощью константных выражений. –
Да, но я понимаю, что даже тогда оно требует определения (без инициализатора) для присутствия в пространстве имен в одной единице перевода; однако в случае шаблона он может отображаться в заголовке и, следовательно, в нескольких TU. Мой вопрос в том, почему символьная коалесцирующая магия, используемая в случае шаблона, не может также использоваться для обычных классов без шаблонов. –
Шаблоны не были частью исходного языка C++. –