由于命名空间问题,C++中出现了无法解释的“未声明”的类错误。

6
我有一些模板类,其中有两个私有静态成员。用户定义了一个特征结构并将其提供给模板类,然后从该结构派生。

然后在C++文件中,用户定义静态成员,其中一个成员从另一个成员初始化。 如果我不完全指定名称空间以用于参数,则会出现“未声明的类”错误,但我不知道原因。只有当我位于嵌套的命名空间中时才会出现此问题,在单个顶级名称空间中定义类型则没有问题,这让我认为这是编译器错误。 下面是简化的示例,使用gcc 7.2编译。

template<typename Traits>
struct Base 
{
    static int x;
    static int y;
};

namespace foo::bar
{
    struct BarTraits
    {
    };

    using Bar = Base<BarTraits>;

    template<> int Bar::x = 0;
    template<> int Bar::y( Bar::x );  //error 
    //template<> int Bar::y( foo::bar::Bar::x ); //no error
}

3
注意以一种假设你的问题无法回答的方式写问题。如果你的错误确实无法解释,那么在这里询问也就没有太大意义了。 - François Andrieux
4
你应该在与“Base”相同的命名空间中定义它们,或者直接从“Traits”模板参数中借用它们。 - user7860670
2
其他编译器在 x 处就会报错,提示 *无法在此定义或重新声明 'x',因为命名空间 'bar' 不包含命名空间 'Basefoo::bar::BarTraits'*。 - Bo Persson
永远不要承认某些东西“让我觉得这是编译器的错误”。 - Jive Dadson
1
template<> int Bar::y( Bar::x ); 并没有定义一个带有初始化器的静态数据成员。在此处您不能使用圆括号作为初始化器。 - StoryTeller - Unslander Monica
VTT - 好的,我能看到,但为什么没有完全指定时,int Bar :: y不会抱怨呢? - ByteMe95
1个回答

0
根据C++标准temp.expl.spec#3

显式特化可以在任何定义相应主模板的作用域中声明。

您的代码违反了这个规定,因为Bar::xBar::y是在namespace foo::bar中进行特化的。

GCC错误地接受了前两个特化,因为存在已知缺陷https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56119

以下是修复后的代码:

template<typename Traits>
struct Base  {
    static int x;
    static int y;
};

struct BarTraits {};
using Bar = Base<BarTraits>;

template<> int Bar::x = 0;
template<> int Bar::y( Bar::x );

被GCC、Clang和MSVC接受:https://gcc.godbolt.org/z/MPxjTzbah


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