Нечто подобное было бы очевидным нарушением правила одного определения С++, если бы оно скомпилировалось:
// Case 1
// something.h
struct S {};
struct A
{
static const S val = S();
};
потому что, если что-то.h будет включено более чем в один модуль, определение A::val
будет повторяться. Однако это разрешено:
// Case 2
// someOtherThing.h
struct B
{
static const int val = 3;
};
Насколько я понимаю, причина, по которой этот случай в порядке, заключается в том, что B::val
является константой времени компиляции целочисленного типа, поэтому компилятор, по сути, может выполнять поиск и замену всех ссылок на B::val
на литерал 3
(и проверку разборка показывает, что это именно то, что он делает). Следовательно, в конечном продукте в некотором смысле ноль определений B::val
, поэтому ODR не применяется. Однако учтите это:
// Case 3
// yetAnotherThing.h
struct C
{
static const int val = 3;
const int* F()
{
return &val;
}
};
Это разрешено, и дизассемблирование показывает, что в этом случае некоторая ячейка памяти фактически была выделена для хранения значения C::val
. На первый взгляд, это означает, что теперь мы нарушаем ODR, если ещеAnotherThing.h включен в несколько модулей, так как static const int val = 3
теперь вызывает «испускание» хранилища. При этом ни компилятор, ни компоновщик (VC++2012) не жалуются.
Почему? Является ли это просто неприятным частным случаем, с которым приходится иметь дело авторам компиляторов/линкеров? И если да, то почему ту же систему нельзя использовать и для случая № 1?
(Соответствующие цитаты из стандарта приветствуются, но они не обязательно отвечают на вопрос. Если бы в стандарте говорилось, что любое использование ключевого слова pink_elephants
должно приводить к замене каждого экземпляра числа 42 на 666, то это было бы так, но мы бы все еще задавались вопросом, почему существует такое странное правило.)
val
идентичны. - person Raymond Chen   schedule 27.05.2014static const double val = 3.0
? Это также запрещено, так какdouble
не является целочисленным, но в этом случае компилятор может сделать вывод, что все определения идентичны, верно? - person dlf   schedule 27.05.2014static const double val = 3.14;
? Это неизвестно до момента компоновки, после чего решение компилятора о том, выдавать ли COMDAT, уже давно не принимается. - person Raymond Chen   schedule 27.05.2014