Clang vs MSVC:模板函数原型的处理
下面是一段测试代码,我分别与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.
The following is a piece of test code, and I'm comparing the result of compiling this with MSVC and Clang respectively. The output of each compiler is shown below. MSVC pretends that the unused template declaration doesn't even exist. Clang produces an error. The question is, which compiler is most standard conformant here?
I have seen legacy production code that relies on the MSVC behavior, and I'm unsure whether or not it can continue to be relied on.
class S
{
struct P {};
};
template<typename T>
S::P Bat(T);
Compiles cleanly in MSVC10:
E:\clangbuild\bin\Release>cl /c /nologo test.cpp
test.cpp
Produces an error in 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于 C++ 中的两阶段名称查找,此操作失败。
在第一阶段,当模板最初被解析时,早在实例化之前,编译器就会解析模板并查找任何非依赖名称。
S::P
是一个非依赖名称,因此编译器尝试查找它,但由于它是私有的而失败。在第 2 阶段,实例化模板时,编译器将查找任何依赖名称,这些名称可能因模板而异。
Clang 相当严格地遵循两阶段名称查找。然而,MSVC 有一个模板解析模型,它几乎延迟了每次查找到实例化时间,这是第 2 阶段的一部分。这种延迟就是为什么您的示例将使用 MSVC(这是不合格的)而不是 clang 进行编译。以下是包含更多信息的链接:
可怕的两相名称查找
另外,这里是 C++ 标准中描述两阶段查找的部分。
14.6.8:
14.6.9:
那么 3.4 名称查找部分适用于您:
通过阅读这些部分可以清楚地看出您的程序格式不正确。该标准规定唯一应该推迟到实例化的事情是依赖名称的查找。非依赖名称会经过通常的名称查找,其中包括访问规则。
This fails because of the two-phase name lookup in C++.
In phase one, when the template is initially parsed, long before it is instantiated, the compiler parses the template and looks up any non-dependent names.
S::P
is a non-dependent name, so the compiler tries to look it up, but fails because it is private.In phase 2, when the template is instantiated, the compiler will lookup any dependent names, which can vary from template to template.
Clang is fairly strictly conforming to the two-phase name lookup. However, MSVC has a template parsing model that delays nearly every lookup to instantiation time, which is part of phase 2. This delay is why your example would compile with MSVC(which is non-conforming) and not in clang. Here is a link with more information:
The Dreaded Two-Phase Name Lookup
Also, here are the sections from the C++ standard where it describes the two-phase lookup.
14.6.8:
14.6.9:
Then the part of 3.4 Name lookup applicable to you:
Its clear from reading these parts that your program is ill-formed. The only thing the standard states that should be postponed until instantiation is the lookup of a dependent name. Non-dependent names go through the usual name lookup, which includes access rules.
编译器实际上只需要检查未实例化模板声明的任何格式错误的语法。任何额外的语义评估仅需要在实例化模板函数时完成。
由于 S::P 确实是一个可以从函数返回的有效类型,因此它们同样一致。
The compiler is only really required to check for any malformed syntax of uninstantiated template declarations. Any additional semantic evaluation only needs to be done when the template function is instantiated.
Since S::P is indeed a type which is valid to be returned from a function, they are both equally conformant.