Это преднамеренно, 9.4.2 / 4 гласит:
Если статический член данных имеет константный интеграл или константный тип перечисления, его объявление в определении класса может указывать инициализатор константы, который долженбыть интегральным константным выражением (5.19). В этом случае член может появляться в виде интегральных константных выражений.Член по-прежнему должен быть определен в области имен, если он используется в программе
Когда вы передаете элемент статических данных по константной ссылке, вы его «используете», 3.2 / 2:
Выражение потенциально оценивается, если только оно не появляется там, где требуется целочисленное константное выражение (см. 5.19), является операндом оператора sizeof (5.3.3) или операндом оператора typeid и выражения.не обозначает lvalue типа полиморфного класса (5.2.8).Объект или не перегруженная функция используется, если его имя появляется в потенциально вычисляемом выражении.
Таким образом, фактически, вы «используете» его, когда передаете его также по значению или в static_cast
.Просто GCC позволил вам снять трубку в одном случае, но не в другом.
[Редактировать: gcc применяет правила из черновиков C ++ 0x: «Переменная или не перегруженная функция, имя которой появляетсяпоскольку потенциально оцениваемое выражение используется в odr, если только оно не является объектом, удовлетворяющим требованиям для появления в константном выражении (5.19), и немедленно применяется преобразование lvalue-to-rvalue (4.1). ".Статическое приведение немедленно выполняет преобразование lvalue-rvalue, поэтому в C ++ 0x оно не «используется».]
Практическая проблема со ссылкой на const заключается в том, что foo
имеет право принимать адресего аргумент, и сравните его, например, с адресом аргумента из другого вызова, хранящегося в глобальном.Поскольку член статических данных является уникальным объектом, это означает, что если вы вызываете foo(kConst)
из двух разных TU, то адрес передаваемого объекта должен быть одинаковым в каждом случае.AFAIK GCC не может организовать это, если объект не определен в одном (и только одном) TU.
OK, поэтому в этом случае foo
является шаблоном, следовательно, определение видно во всех TU, поэтомувозможно, теоретически компилятор может исключить риск того, что он что-то сделает с адресом.Но в целом вы, конечно, не должны брать адреса или ссылки на несуществующие объекты; -)