нестатические элементы данных и одно правило определения


Предпосылка

В соответствии с правилом одного определения, Как указано в стандарте C++14, я могу иметь определение одного и того же класса в каждой единице перевода, пока я следую правилам в 3.2.6. Это означает, что следующая программа может быть легальной:

//a_1.cpp
class A {                      //definition of A
    int a;                     //definition of A::a
    static int b;              //declaration of A::b
    int foo();                 //declaration of A::foo();
    int boo(){ return 42; };   //definition of A::boo() implicity inlined 
};

//a_2.cpp
class A {                      //definition of A
    int a;                     //definition of A::a
    static int b;              //declaration of A::b
    int foo();                 //declaration of A::foo();
    int boo(){ return 42; };   //definition of A::boo() implicity inlined 
};

Если я попытаюсь определить b или foo(), я, однако, ограничусь одним определением во всей программе, которое, как я полагаю, связано с утверждением в 3.2.4:

Каждая программа должна содержать ровно одно определение каждой нестрочной функции или переменной, которая используется odr в этой программе не требуется никакой диагностики.

По этой причине плохо сформирована следующая программа:
//a_1.cpp
class A {                      //definition of A
    int a;                     //definition of A::a
    static int b;              //declaration of A::b
    int foo();                 //declaration of A::foo();
    int boo(){ return 42; };   //definition of A::boo() implicity inlined 
};
int A::b;

//a_2.cpp
class A {                      //definition of A
    int a;                     //definition of A::a
    static int b;              //declaration of A::b
    int foo();                 //declaration of A::foo();
    int boo(){ return 42; };   //definition of A::boo() implicitly inlined 
};
int A::b;

То же самое, если бы я попытался определить foo() в обоих исходных файлах.

Я могу, однако, иметь несколько определений boo() (по одному на единицу перевода), поскольку это не запрещено 3.2.4 и, фактически, явно разрешено 3.2.6:

Может быть более одного определения типа класса (пункт 9), типа перечисления (7.2), встроенной функции с внешняя связь (7.1.2), шаблон класса (пункт 14), шаблон нестатической функции (14.5.6), статический элемент данных шаблона класса (14.5.1.3), функции-члена шаблона класса (14.5.1.1) или специализации шаблона для которые некоторые параметры шаблона не указаны (14.7, 14.5.5) в программе при условии, что каждое определение появляется в другом единица перевода.

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

Вопрос

Как насчет нестатического элемента данных a? Очевидно, что допускается несколько определений a (в противном случае программа в верхней части моего вопроса не компилировалась бы), но это, по-видимому, запрещено 3.2.4 и не потворствует 3.2.6. Это просто деталь, не строго оговоренная в стандарте, или я что-то упустил?

Edit

Для тех, кто указал мне, что a не определен, а просто объявлен, пожалуйста, рассмотрим этот пример, взятый прямо из стандарта C++14, 3.2.2:

struct X { // defines X
    int x; // defines non-static data member x
    static int y; // declares static data member y
    X(): x(0) { } // defines a constructor of X
};

Пожалуйста, не думайте, что комментарии к приведенному выше коду не мои, а скопированы прямо из стандарта.

2 4

2 ответа:

[основной.защита.odr]/1:

Ни одна единица перевода не должна содержать более одного определения какой-либо переменной, функции, типа класса, типа перечисления или шаблона.

переменная определяется [basic]/6:

Переменнаявводится объявлением ссылки, отличной от нестатического элемента данных или объекта.

Таким образом, поскольку нестатический элемент данных не является переменной, функцией, классом, перечислением или шаблоном, то одно правило определения просто не применяется к нестатическим элементам данных.

У вас нет нескольких определений из a в первой программе. У вас есть несколько объявлений из a. Огромное отличие.

Если вы не можете иметь несколько объявлений, то include не будет работать, поскольку препроцессор просто копирует эту информацию в каждом переводе, в котором он используется.