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 上测试的,到目前为止看起来有点像一个错误......)

4

2 回答 2

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,但是,h是在范围内g,所以专业化也在范围内g,这在技术上可以做到这一点。但是,通过这种推理,您可以在任何地方都专门化一个模板,因为您总是在包含所有内容的全局命名空间中。所以我很确定 GCC 在这里的行为过于宽容,而且是一个错误。您也应该使用其他编译器尝试此操作,然后提交错误,或者可能针对标准提交缺陷报告。

于 2014-01-10T10:35:41.647 回答
-1

在:

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

它失败是因为与关联的命名空间F<int>::n_sg,而X在 中声明g::h。这就是为什么您需要将其拼写为h::F<int>::n_s.

于 2014-01-10T10:29:08.547 回答