警告:不同命名空间中模板的特化

时间:2014-08-31 17:46:50

标签: c++

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

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 ++没有)。

2 个答案:

答案 0 :(得分:17)

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

  

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

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

请参阅CWG issue 374GCC bug 56480

答案 1 :(得分:7)

这里有一个明显的问题,一个潜在的隐形问题。可见问题是此代码不在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