Нетипичные (справочные) параметры шаблона и связи

В следующих,

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?
  • кто прав? GCC или лязг?

2

Решение

Как указывает Керрек в комментарии, уровень пространства имен const переменные имеют внутреннюю связь (если вы не используете extern ключевое слово). В C ++ 03 вы не можете использовать указатель или ссылку на переменную с внутренней связью в качестве нетипового аргумента шаблона. Это ограничение было снято в C ++ 11. Кажется, что ваша версия gcc работает по правилам C ++ 03, в то время как компилятор clang использует правила C ++ 11.


14.3.2 [temp.arg.nontype] / 1

Шаблон-аргумент для нетипового, не шаблонного Шаблон-параметр должен быть одним из:

  • […]
  • константное выражение (5.19), которое обозначает адрес объекта с статическая продолжительность хранения и внешняя или внутренняя связь
    или функция с внешней или внутренней связью, включая функцию
    шаблоны и идентификаторы шаблонов функций, но исключая нестатический класс
    члены, выраженные (игнорируя скобки) как & id-выражение, кроме
    что & может быть опущено, если имя относится к функции или массиву
    и должен быть опущен, если соответствующий шаблон-параметр является
    ссылка; или же
  • […]
4

Другие решения

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 удовлетворяет вышеуказанному требованию и должно быть разрешено в качестве нетипичного аргумента.

3

Это ошибка, однако она известна (и она просто еще не реализована, по крайней мере до gcc 4.9).

Здесь сообщение об ошибке

Я ожидаю, что в gcc 5.0 это будет реализовано, поскольку в 5.0 добавлено много новых функций C ++ 11.

2
По вопросам рекламы [email protected]