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

19
以下代码会出现警告: 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++则不会。)


这似乎是与这个问题所报告的相同问题。 - nonsensickle
1
为什么不允许将模板特化放在不同的命名空间中?可能会对您感兴趣。 - nonsensickle
2个回答

22
假设您是在C++11模式下编译此代码(因为clang没有警告),而此专业化是在全局命名空间中,那么您的代码没有任何问题。这是g ++的错误。§14.7.3 [temp.expl.spec] / p2:
“显式特化应在包围专门模板的命名空间中声明。未限定的显式特化应在模板的最近封闭命名空间中声明,或者如果该命名空间是内联的(7.3.1),则在其封闭命名空间集中的任何命名空间。这样的声明也可以是定义。如果声明不是定义,则稍后可以定义专业化(7.3.1.2)。“
全局命名空间是“包含专门模板的命名空间”,您的declarator-id是使用std :: 限定的,因此第二个句子不适用。作为一种解决方法,您可以执行cdhowie答案建议的操作 - 即打开一个namespace std 块并在其中放置专门化。
请参见CWG问题374 GCC bug 56480

1
真烦人。看起来gcc直到7.0版本才解决了它。 - Justin

13

这里有一个显而易见的问题和一个潜在的不可见的问题。 显而易见的问题是,这段代码没有在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不嵌套在任何其他命名空间块内。

进一步阅读:在不同命名空间中特化'template<class _Tp> struct std::less'


1
问题在于先关闭命名空间块。从宏中无法实现,因为您不知道将要扩展到哪里。 - v.oddou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接