非实例化C++模板函数的语义正确性

use*_*999 5 c++ templates instantiation

以下C++代码无法编译,例如使用g ++ - 4.7或clang ++ - 3.2:

struct Bar {};

template<typename T>
void foo(T t, Bar bar) {
    t.compiler_does_not_care();
    bar.nonexistent_method();
}

int main() {}
Run Code Online (Sandbox Code Playgroud)

为什么编译器检查模板函数foo的代码是否具有语义正确性(他们可以在哪里),即使它从未实例化过?这个标准是否合规?

qua*_*dev 7

Bar是一个非依赖名称(即它的类型不依赖T),因此编译器需要在名称查找的第一阶段验证代码的正确性(请参阅下面的注释).

由于Bar没有nonexistent_method()方法,编译器需要发出诊断.

如果您将模板更改为:

template<typename T>
void foo(T t, T bar) {
    t.compiler_does_not_care();
    bar.nonexistent_method();
}
Run Code Online (Sandbox Code Playgroud)

不涉及非依赖名称,因此不会发出错误,因为模板从未实例化(查找的第2阶段)


笔记:

  • LLVM中可理解的两阶段名称查找描述:

1)模板定义时间:最初解析模板时,在实例化之前,编译器会解析模板并查找任何"非依赖"名称.如果名称查找的结果不依赖于任何模板参数,则名称是"非依赖的",因此从一个模板实例到另一个模板实例将是相同的.

2)模板实例化时间:当模板被实例化时,编译器查找任何"依赖"名称,现在它具有完整的模板参数集来执行查找.这种查找的结果可以(并且经常会!)从一个模板实例化到另一个模板实例化.

  • 至于为什么非依赖名称查找不能推迟到第二阶段,请参阅其他SO帖子 ; 它似乎主要是出于历史原因.