为什么函数范围内不允许类前置声明?

3

以下代码可以正常工作:

template<typename T> class X {};
class A;  // line-1
void foo();  // line-2
int main ()
{
  X<A> vA;
}
class A {};
void foo() {}

让line-1和line-2移动到main()之内。函数不会受影响,但class A的前向声明不起作用,并且会出现编译错误

错误:模板参数template<class T> class X使用了局部类型main()::A


据我所知,将不完整类型用作 std::vector 的模板参数是未定义的行为(UB)。顺便提一句,如果你想要一个律师问题,可能需要自己想出一个简单的类型,比如 template <typename> struct Empty{};,然后给它赋值 Empty<A> vA;。(或者这确实只适用于 std::vector?) - GManNickG
@GManNickG,已编辑问题。这是用于template的通用使用。 - iammilind
2个回答

4
你所观察到的现象是由于在C++中可以在函数内定义类。 因此,如果你在main里放置了 class A;,你就是在这个函数的作用域内前向声明一个类(即 class main::A),而不是在全局作用域内声明一个类(class A)。
因此,你最终声明了一个带有未定义类的模板参数类型X (X<main::A>)的对象。

2
你最终声明了一个类型为X的对象,使用未定义类的模板参数。现在使用的模板是X而不是vector,我认为main :: A是不完整类型并不是问题。在C++03中,将本地类型用作模板参数是非法的(14.3.1/2)。据我所知,在C++11中取消了此限制。 - Steve Jessop

2

错误: 模板类X的模板参数使用了本地类型main()::A

这是真正的问题——使用本地类型。在C++03中,您不能将本地类型用作模板参数,因为没有人想出如何命名生成的类型。

如果您在几个重载函数中有几个名为class A的类(再次使用相同的名称),那么生成的X<A>是否是相同的类型还是不同的类型?怎么区分它们?

在C++03中,标准放弃了这个问题,并且只是说“别那样做!”。

在C++11中,通过决定使用本地类型AX<A>与在函数外部的匿名命名空间中声明A相同来解决了这个问题。

namespace
{
    class A
    { };
}

int main()
{
    X<A>   vA;
}

因此,使用更新的编译器(或使用-std=cpp11选项),您可以使用本地类,并且我们也知道它的含义。


但是,在函数内部前向声明类型仍然与在另一个作用域中前向声明不同。它们将只是不同的类型。


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