C ++模板实例化混淆点

时间:2014-07-07 20:43:29

标签: c++ templates

我对C ++中的实例化有点困惑。考虑以下代码(在VC ++ 2012下编译正常):

struct Foo;

template <class T> Foo* Create() { return new Foo; }

Foo* MyFoo = Create<int>();

// (A) I expected point of instantiation to be here

struct Foo {};

// (B) But it appears to be here instead

我期望实例化的点是上面的点(A),但显然不是这种情况(因为Foo在点(A)处是不完整的类型)。任何人都可以解释为什么这个编译?这是标准行为还是MSVC的怪癖?

编辑:为了澄清,我真正想知道的是:这是一个有效的程序吗?编译器是否应该接受它,为什么? (显然,如果编译器接受该程序而不应该接受该程序,那么这是MSVC的不符合行为。)

1 个答案:

答案 0 :(得分:2)

让我们从顶部开始吧。 Create()的定义无效,因为它试图为正文中的不完整类型分配内存。但是,您可以在此处声明此函数并在以后定义它。

Create<int>()的声明很好 - 允许声明指向不完整类型的指针,或允许返回一个的函数。

当然,如果从代码末尾删除Foo的定义,编译器就会到达最后并意识到它从未看到过Foo类型的定义。然后,不是在定义之前的不完整类型,而是Foo结构只是未定义的,任何引用它的代码都将无法编译。

程序无效(尝试定义分配不完整类型的函数)

struct Foo;
template <class T> Foo* Create() { return new Foo; }
Foo* MyFoo = Create<int>();
struct Foo {};

程序的有效版本(移动分配Foo的函数定义到最后):

struct Foo;
template <class T> Foo* Create();
Foo* MyFoo = Create<int>();
struct Foo {};
template <class T> Foo* Create() { return new Foo; }

该程序在g ++下编译,据我所知是完全允许的。 标准的相关部分:

<强> 5.3.1p1 “通过指向不完整类型(cv void除外)的指针的间接是有效的。这样获得的左值可以以有限的方式使用(例如,初始化引用);此左值不能转换为prvalue”

<强> 8.3.5p9 “不应在返回或参数类型中定义类型。函数定义的参数类型或返回类型不应是不完整的类类型”