Это должно быть целочисленное константное выражение. Это объясняется стандартным документом на 5.19
:
Интегральное константное выражение может включать только литералы (2.13), перечислители, константные переменные или члены-статические данные целочисленных или перечислимых типов, инициализированных константными выражениями (8.5), нетиповые шаблонные параметры целочисленных или перечислимых типов и sizeof выражения. Плавающие литералы (2.13.3) могут появляться, только если они приводятся к целочисленным или перечислимым типам. Можно использовать только преобразования типов в целочисленные или перечислимые типы.
Обратите внимание, что «интеграл» - это еще один термин для «целого числа», но он не совпадает с «int». Например, char имеет целочисленный / целочисленный тип, но, очевидно, не является типом int. Итак, конкретно, разрешено следующее
10 or 10L or anything like that
enum { THIS, OR, THAT };
int const this_one = 10;
sizeof(char)
- конечно, любой другой параметр шаблона, как описано выше
Любой из них может использоваться в качестве аргумента шаблона для параметра, который имеет целочисленный тип соответствующего типа. Некоторые преобразования все еще применяются, хотя. Так что, если он хочет получить int и вы передаете char, он автоматически продвигает его в int. То же самое, если вы предоставляете перечислитель, и он хочет int.
Итак, по этим правилам, если у вас есть
extern const int SomeName;
И он не видит определения, которое инициализирует эту константу с помощью целочисленного константного выражения, его нельзя использовать в качестве аргумента шаблона. Но, конечно, его можно использовать в качестве аргумента функции. Их не нужно знать во время компиляции, потому что они не являются частью типа. В момент, когда вы называете специализацию шаблона, используемые вами аргументы становятся частью типа:
MyGreatStack<int, 4> // 4 is now part of the type MyGreatStack<int, 4>!
Обратите внимание, что есть другие способы передачи SomeName
в качестве аргумента. Однако все это может не быть принято целочисленным параметром шаблона. Вы можете принять вышеупомянутое с помощью ссылочного параметра, например
template<const int& V> struct NowItWorks { };
И он принял бы SomeName
выше. Теперь вместо значения выбрано определенное местоположение, уникальное для всей программы (так как переменная имеет extern
связь).