模板方法访问前向声明的类,没有this指针编译失败

4
当我使用最新的Visual Studio编译以下代码时,编译成功。
class C;

class T
{
public:
    template<typename A>
    void f();

private:
    C* c;
};

int main()
{
    T t;
    t.f<int>();
}

template<typename A>
void T::f()
{
    this->c->g();
}

class C
{
public:
    void g() {}
};

当我从this->c->g()中删除this->时,编译失败,显示C2027:使用未定义类型“C”

当我将方法f设为非模板函数时,无论是否出现this->,都无法编译通过,因此我认为这与模板的编译/实例化相关,但我真的无法确定。我已阅读此答案,但在T::f()中,cg不是不含糊的吗?

所以,问题是:this->在这里起什么作用?


编译器差异:

+-----------------------+---------------------+----------------------+--------------+
|                       | Template, w/ this-> | Template, w/o this-> | Non-Template |
+-----------------------+---------------------+----------------------+--------------+
| Visual Studio 16.3.10 | Success             | Fail                 | Fail         |
| x64 msvc v19.24       | Success             | Success              | Fail         |
| x86-64 gcc 9.2        | Success w/ warning  | Success w/ warning   | Fail         |
| x86-64 clang 9.0.0    | Fail                | Fail                 | Fail         |
+-----------------------+---------------------+----------------------+--------------+

编译器浏览器测试了x64 msvc v19.24x86-64 gcc 9.2x86-64 clang 9.0.0


2
我认为这个代码应该无法编译通过,所以只有clang是正确的。当T.f<int>()第一次被实例化时,它还没有C的定义,因此应该失败。 - ChrisMM
@ChrisMM 嗯,它应该在模板定义时失败,而不仅仅是在实例化时失败。GCC也“正确”,因为它知道它应该失败。 - HTNW
@HTNW,为什么模板定义不可以?如果将定义“C”移动到“template<typename A> void T::f()”定义之前,那么就是正确的。或者,这就是你的意思吗? - ChrisMM
@ChrisMM T 不依赖于 A,因此 this 不依赖于 A,因此对 c 的访问不依赖于 A,因此在 C 中访问 g 不依赖于 A,因此应该在模板的定义处进行检查而不是在实例化时进行,因此模板本身就是有问题的。如果在模板定义处可见 C 的定义,则它将是良好的形式。 - HTNW
@HTNW,“在模板定义中使用的非依赖名称是使用通常的名称查找找到的,并且在使用它们的点上绑定。” 在 OP 的示例中,this->c->g() 不在模板定义中使用,只在 T::f() 定义中使用。由于 c(带或不带 this)尚未具有 C 的完整定义,因此仍然是错误的。所以,是的,不像我在第一条评论中说的那样,不是 T.f<int>() 的实例化。而是在定义 T::f() 时。 - ChrisMM
显示剩余3条评论
1个回答

1
由于C++17 [temp.res]/8.3,该程序是不规范的NDR:
如果:一个模板的假设实例化紧随其定义而产生的结果是不规范的,这是不需要进行诊断的。
由于使用指向不完整类型的指针 c ,并且这不受模板参数 A 的影响,因此假定的实例化是不规范的。
因此,是否引发错误是实现质量问题。

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