Clang vs MSVC:模板函数原型的处理

时间:2012-02-16 00:33:04

标签: c++ templates visual-c++ clang

以下是一段测试代码,我将分别编译它与MSVC和Clang的结果进行比较。每个编译器的输出如下所示。 MSVC假装未使用的模板声明甚至不存在。 Clang产生错误。问题是,哪个编译器最符合标准?

我见过依赖于MSVC行为的遗留生产代码,我不确定它是否可以继续依赖。

class S
{
    struct P {};
};

template<typename T>
S::P Bat(T);

在MSVC10中完全编译:

E:\clangbuild\bin\Release>cl /c /nologo test.cpp
test.cpp

在Clang中产生错误:

E:\clangbuild\bin\Release>clang++ test.cpp
test.cpp:9:4: error: 'P' is a private member of 'S'
S::P Bat(T);
   ^
test.cpp:5:9: note: implicitly declared private here
struct P {};
        ^
1 error generated.

2 个答案:

答案 0 :(得分:4)

由于在C ++中进行两阶段名称查找,因此失败。

在第一阶段,当模板最初被解析时,早在实例化之前,编译器就会解析模板并查找任何非相关名称。 S::P是一个非依赖名称,因此编译器会尝试查找它,但由于它是私有的而失败。

在阶段2中,当模板被实例化时,编译器将查找任何依赖名称,这些名称可能因模板而异。

Clang非常严格地符合两阶段名称查找。但是,MSVC有一个模板解析模型,它几乎将每个查找延迟到实例化时间,这是第2阶段的一部分。这个延迟是你的例子用MSVC(不符合条件)而不是clang编译的原因。这是一个包含更多信息的链接:

The Dreaded Two-Phase Name Lookup

此外,以下是C ++标准中描述两阶段查找的部分。

14.6.8:

  

查找模板中使用的名称声明时   定义,通常的查找规则(3.4.1,3.4.2)用于   非依赖名称。查找依赖于模板的名称   参数被推迟,直到知道实际的模板参数。

14.6.9:

  

如果名称不依赖于模板参数(如中所定义)   14.6.2),该名称的声明(或一组声明)应在名称出现在模板中的范围内   定义;名称与声明(或声明)绑定   在那一点上找到并且此绑定不受声明的影响   在实例化时可见。

然后3.4名称查找的部分适用于您:

  

访问规则(第11条)仅被视为名称查找和   函数重载决策(如果适用)已成功。只要   名称查找后,函数重载解析(如果适用)和   访问检查成功是由...引入的属性   name的声明在表达式处理中进一步使用(第5条)。

从阅读这些部分可以清楚地看出你的程序是不正确的。标准规定应该推迟到实例化的唯一事情是查找依赖名称。非依赖名称通过通常的名称查找,其中包括访问规则。

答案 1 :(得分:3)

只需要编译器检查未实例化的模板声明的任何格式错误的语法。只有在实例化模板函数时才需要进行任何额外的语义评估。

由于S :: P确实是一个有效从函数返回的类型,因此它们同样符合要求。