Каковы правила C ++, касающиеся специализации шаблонов и квалификации пространства имен? У меня был некоторый код, который сводился к эквиваленту следующего, и это заставило меня понять, что я не понимаю правила C ++, касающиеся инициализации специализации шаблона. Во-первых, мне кажется странным, что специализации g::F<>
даже разрешено внутри h
Но, учитывая это, я не знаю, почему вещи действуют так, как они.
namespace g {
struct N {
N(char c):c_(c){}
char c_;
};
template <typename V>
struct F {
static N n_s; // <-- want to initialize these for specializations
};
namespace h {
struct X { static constexpr char k{'x'}; };
template <> N F<char>::n_s{h::X::k}; // OK
template <> N F<int>::n_s{X::k}; // fails on "‘X’ not declared"}
} // namespace g
// Seems weirdest to me. N and F need full qualifications but X doesn't.
template <> g::N g::F<float>::n_s{h::X::k}; // OK also!
Последний экземпляр / инициализация, где инициализатор статического члена шаблона выводит g
Пространство имен создает впечатление, будто шаблон действует так, как будто инициализатор действует так, как если бы он находился в том же месте кода, что и само определение шаблона.
Какое правило спецификации определяет это поведение? (Обратите внимание, что это было протестировано на gcc 4.8.1, и до сих пор выглядит как ошибка …)
Ключевое замешательство здесь не в специализации, а в квалификации. Давайте посмотрим на последнюю специализацию (в глобальном пространстве имен), чтобы проиллюстрировать это:
template <> g::N g::F<float>::n_s{h::X::k};
Когда линия начинается, вы находитесь в глобальном пространстве имен. Таким образом, g::N
обязательно квалифицирован, как есть g::F<float>
,
Тем не менее, в тот момент, когда вы перестали специализироваться (т.е. после n_s
), теперь вы находитесь в сфере того, что вы специализируете, то есть внутри g::F
, Весь дальнейший поиск выполняется изнутри этой области, поэтому x
должен быть квалифицирован как h::X
,
Тем не менее, в то время как разрешено специализировать вещи в пространстве имен, которое охватывает исходное пространство имен, специализирующемся во вложенном пространстве имен (h
в вашем случае) выглядит странно для меня, но стандарт здесь слегка двусмысленный, как сказано в 14.7.3 / 2: «Явная специализация должна быть объявлена в пространстве имен, включающем специализированный шаблон».
Глобальное пространство имен охватывает F
так что все нормально, как есть g
, h
не вмещает F
, но потом, h
внутри g
так что специализация находится в пределах g
тоже, что технически делает это хорошо. Однако, исходя из этих соображений, вы можете специализировать шаблон абсолютно везде, потому что вы всегда находитесь внутри глобального пространства имен, которое охватывает все. Так что я почти уверен, что поведение GCC здесь слишком допустимо, и это ошибка. Вы должны попробовать это и с другими компиляторами, а затем подать ошибку или, возможно, отчет о дефектах по сравнению со стандартом.
В:
template <> N F<int>::n_s{X::k}; // fails on "‘X’ not declared"
Сбой, потому что пространство имен связано с F<int>::n_s
является g
, в то время как X
объявлен в g::h
, Вот почему вы должны изложить это как h::F<int>::n_s
,