首页 > 解决方案 > 为什么即使直到最后才定义实际类型,从属名称也可以被认为是完整的

问题描述

考虑这个例子

template <class T>
void Yeap(T);

int main() {
    Yeap(0);
    return 0;
}

template <class T>
void YeapImpl();

struct X;

template <class T>
void Yeap(T) {
    YeapImpl<X>(); // pass X to another template
}

template <class T>
void YeapImpl() {
    T().foo();
}

struct X {
    void foo() {}
};

请注意,struct X直到最后才定义。我曾经相信所有使用 odr 的名称在实例化时都必须是完整的。但是在这里,编译器如何在定义之前将其视为完整类型?

我已经检查了 cppreference 中依赖名称和函数模板实例化的绑定规则和查找规则,但它们都无法解释这里发生了什么。

标签: c++templatesc++17dependent-name

解决方案


我相信这个程序格式不正确,不需要诊断。

[temp.point]/8读取,编辑掉不相关的部分:

函数模板的特化 [...] 可能在翻译单元内具有多个实例化点,并且除了上述实例化点之外,对于在翻译单元内具有实例化点的任何此类特化,结束翻译单元也被认为是一个实例化点。[...] 如果两个不同的实例化点根据单一定义规则赋予模板特化不同的含义,则程序格式错误,不需要诊断。

YeapImpl<X>有两个实例化点:在问题的注释行和翻译单元的末尾调用它。在实例化的第一点,X是不完整的,这会使函数的主体格式不正确。在实例化的第二点中,X是完整的,这使得主体结构良好。

这两个专业有[非常]不同的含义。


推荐阅读