【问题标题】:warning: specialization of template in different namespace警告:模板在不同命名空间中的特化
【发布时间】:2014-08-31 17:46:49
【问题描述】:

使用以下代码我收到警告:

warning: specialization of ‘template<class _Iterator> struct std::iterator_traits’ in different namespace [-fpermissive]

template<> class std::iterator_traits<Token_ptr>{
public:
    typedef Word difference_type;
    typedef Word value_type;
    typedef Token_ptr pointer;
    typedef Word& reference ;
    typedef std::bidirectional_iterator_tag iterator_category ;
};

虽然一切正常,但是否有人知道发出警告的确切含义以及发出警告的原因。 (g++ 发出警告,而 clang++ 没有)。

【问题讨论】:

标签: c++


【解决方案1】:

假设你在 C++11 模式下编译它(因为 clang 没有给出警告)并且这个特化是在全局命名空间中,那么你的代码没有任何问题。这是一个 g++ 错误。 §14.7.3 [temp.expl.spec]/p2:

一个明确的特化应该在一个封闭的命名空间中声明 专门的模板。一个明确的专业化,其 declarator-id 不合格应在模板的最近封闭命名空间中声明,或者,如果命名空间是内联的 (7.3.1),来自其封闭命名空间集中的任何命名空间。这样一个 声明也可以是定义。如果声明不是 定义,专业化可能会在以后定义(7.3.1.2)。

全局命名空间是一个“包含专用模板的命名空间”,并且您的 declarator-idstd:: 限定,因此第二句不适用。作为一种解决方法,您可以执行cdhowie 的回答所建议的操作 - 即打开一个namespace std 块并将专业化放在那里。

参见CWG issue 374GCC bug 56480

【讨论】:

  • 真烦人。似乎 gcc 直到 7.0 版才修复它
【解决方案2】:

这里有一个可见的问题,还有一个潜在的不可见问题。可见的问题是此代码不在namespace std 块中。要专门化一个模板,您需要位于您专门化的模板的命名空间内。在这种情况下,将命名空间名称作为类型的一部分实际上不起作用。所以你需要这样做:

namespace std
{
    template<> class iterator_traits<Token_ptr>{
    public:
        typedef Word difference_type;
        typedef Word value_type;
        typedef Token_ptr pointer;
        typedef Word& reference ;
        typedef std::bidirectional_iterator_tag iterator_category ;
    };
}

另一个潜在的问题是这段代码可能已经在另一个namespace 块内(我无法确定,因为这可能不是整个源文件)。如果是,您需要先关闭该命名空间块,以便namespace std 不会嵌套在任何其他命名空间块中。

延伸阅读:Specialization of 'template<class _Tp> struct std::less' in different namespace

【讨论】:

  • 问题是closing that namespace block first。从宏中是不可行的。因为你不知道你会在哪里扩展。
猜你喜欢
  • 2015-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 1970-01-01
  • 2014-11-17
  • 1970-01-01
相关资源
最近更新 更多