0

什么是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测试,看起来迄今有点像一个bug ......)

回答

-1

在:

template <> N F<int>::n_s{X::k};  // fails on "‘X’ not declared" 

它失败,因为与F<int>::n_s相关的命名空间是g,而Xg::h中声明。这就是为什么你需要把它拼出来,如h::F<int>::n_s

+0

呵呵?你的意思是拼出来像g :: F :: n_s?我可以清楚地看到,它必须像使用命名空间g一样被限定,不管它在哪里使用,但我不明白为什么在h中允许初始化,或者为什么要在f中使用F :: n_s {h :: X :: k}初始化允许在g之外,而不需要额外的g :: qualifier ... – Jeff

2

这里关键的困惑不在于专业化,而在于资质。让我们来看看最后的专业化(在全局命名空间)来说明这一点:

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,但是hg之内,所以专业化也在g之内,这在技术上使这很好。然而,通过这个推理,你可以绝对无处不在的专门化一个模板,因为你总是在全局命名空间里面,它包含了所有的东西。所以我很确定GCC在这里的行为过于宽容,并且存在一个bug。您应该尝试与其他编译器一起使用,然后提交错误报告,或者根据标准提交缺陷报告。

+0

谢谢,这是我所怀疑的,但是我在阅读规范时找不到直接的矛盾。我试图将一个像F这样的模板混入到像h这样的嵌套命名空间中,当我将它蒸馏到上面最简单的情况/行为时。 – Jeff