В следующих,
int i{3};
const int j{3};
extern const int k{3};
template <typename T, T&>
void f() {}
int main()
{
f<int, i>(); // OK
f<int const, j>(); // not valid template argument: 'j' has not external linkage
f<int const, k>(); // OK
}
GCC выдает ошибку для использования j
в качестве параметра шаблона, в то время как clang компилируется нормально.
i
, j
?const
/ не-const
?Как указывает Керрек в комментарии, уровень пространства имен const
переменные имеют внутреннюю связь (если вы не используете extern
ключевое слово). В C ++ 03 вы не можете использовать указатель или ссылку на переменную с внутренней связью в качестве нетипового аргумента шаблона. Это ограничение было снято в C ++ 11. Кажется, что ваша версия gcc работает по правилам C ++ 03, в то время как компилятор clang использует правила C ++ 11.
14.3.2 [temp.arg.nontype] / 1
Шаблон-аргумент для нетипового, не шаблонного Шаблон-параметр должен быть одним из:
- […]
- константное выражение (5.19), которое обозначает адрес объекта с статическая продолжительность хранения и внешняя или внутренняя связь
или функция с внешней или внутренней связью, включая функцию
шаблоны и идентификаторы шаблонов функций, но исключая нестатический класс
члены, выраженные (игнорируя скобки) как & id-выражение, кроме
что & может быть опущено, если имя относится к функции или массиву
и должен быть опущен, если соответствующий шаблон-параметр является
ссылка; или же- […]
i
имеет внешнюю связь в то время как j
имеет внутреннюю связь. Эти правила перечислены в §3.5 [basic.link]
4 Безымянное пространство имен или пространство имен, объявленное прямо или косвенно в безымянном пространстве имен, имеет внутреннюю связь. Все остальные пространства имен имеют внешнюю связь. Имя, имеющее область пространства имен, которой не была предоставлена внутренняя связь выше, имеет ту же связь, что и вмещающее пространство имен если это имя
— Переменная; или же
— …
Глобальное пространство имен имеет внешнюю связь, следовательно i
также имеет внешнюю связь (поскольку она явно не объявлена как имеющая внутреннюю связь).
3 Имя, имеющее область имен (3.3.6), имеет внутреннюю связь, если это имя
— …
— энергонезависимая переменная, которая явно заявлено Const или же constexpr и ни одно явно не заявлено внешний и ранее не было заявлено о наличии внешней связи; или же
— …
j
явно объявлено const
без объявления extern
следовательно, он имеет внутреннюю связь.
Я считаю, что лязг в этом случае правильный из-за §14.3.2 / 1 [temp.arg.nontype]
Шаблон-аргумент для нетипового, не шаблонного Шаблон-параметр должен быть одним из:
— …
— константное выражение (5.19), которое обозначает адрес полного объекта со статической продолжительностью хранения и внешней или внутренней связью …
j
удовлетворяет вышеуказанному требованию и должно быть разрешено в качестве нетипичного аргумента.
Это ошибка, однако она известна (и она просто еще не реализована, по крайней мере до gcc 4.9).
Здесь сообщение об ошибке
Я ожидаю, что в gcc 5.0 это будет реализовано, поскольку в 5.0 добавлено много новых функций C ++ 11.