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

时间:2014-08-20 13:25:28

标签: 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() {}

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

1 个答案:

答案 0 :(得分:7)

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

由于Bar没有nonexistent_method()方法,因此编制者需要发出诊断。

如果您将模板更改为:

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

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


备注:

  • 来自LLVM的两阶段名称查询的可理解描述:
  

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

     

2)模板实例化时间:当模板被实例化时,编译器会查找任何依赖的&#34;名字,现在已经满了   用于执行查找的模板参数集。结果如此   查找可以(通常也是!)从一个模板实例化到   另一个。

  • 至于为什么非依赖名称查找不能推迟到第二阶段,请参阅this other SO post;似乎这主要是出于历史原因。