为什么依赖名称可以被认为是完整的,即使实际类型直到最后才定义

fel*_*lix 9 c++ templates dependent-name c++17

考虑这个例子:

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() {}
};
Run Code Online (Sandbox Code Playgroud)

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

我已经检查了cppreference中的依赖名称和函数模板实例化的绑定规则和查找规则,但是没有一个能够解释这里发生的事情.

Bar*_*rry 8

我相信这个程序是不正确的,不需要诊断.

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

函数模板的特化可以在翻译单元中具有多个实例化点,并且除了上述实例化点之外,对于在翻译单元内具有实例化点的任何这样的专业化,结束翻译单位也被认为是实例化的一个方面.[...]如果两个不同的实例化点根据一个定义规则给出模板特化的不同含义,则程序形成错误,无需诊断.

YeapImpl<X>有两个实例化点:在问题的注释行和翻译单元的末尾调用它.在实例化的第一点,X是不完整的,这将使功能的主体形成不良.在实例化的第二点,X完成使身体形成良好.

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

  • 我总是忘记实例化是一种(非显式)专业化.我应该用[`[temp.spec]/4`]纹身我的前臂(http://eel.is/c++draft/temp.spec#4.sentence-2)...... (2认同)