我有以下 C++ 代码:
//Define to 1 to make it work
#define WORKS 0
#if WORKS
template< typename T > struct Foo;
#else
template< typename T >
struct Foo {
T t;
};
#endif
class Bar; //Incomplete type
void fFooBar(Foo<Bar> const & foobar) { }
void f(Foo<Bar> const & foobar) {
fFooBar(foobar);
}
int main() {
return 0;
}
如果 WORKS 被定义为 0(结构模板被定义)代码不会编译,因为它试图在 fFooBar(foobar);
实例化它并且失败,因为 Bar
不完整。
如果 WORKS 定义为 1(结构模板未定义),代码编译。
根据标准,不应实例化模板,除非需要完整的类型(const&
不是这种情况)或者它会改变代码的语义(这又是事实并非如此,如果模板未定义,同样的情况也会发生。
此外,通过从编译单元中删除信息可以使程序编译,这很奇怪。但事实上 MSVC、gcc 和 clang 都做同样的事情 让我觉得这背后一定有原因。
最佳答案
当 WORKS=0
时,通过使用 ::
限定对 fFooBar
的调用,可以使程序在 Clang 中编译。该标准要求在函数调用中使用非限定名称时,名称查找的行为有所不同。
[basic.lookup.argdep]/1
When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope friend function declarations (11.3) not otherwise visible may be found.
检查 Argument Dependent Lookup 过程的(有些复杂的)规则表明,它只能以需要在调用参数类型中实例化模板特化的方式正确实现。
[basic.lookup.argdep]/2
For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments [...]
- If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes.
对此的一种解释是,如果类用于非限定函数调用的参数类型,则该类必须是完整的。另一种解释是 ADL 应该只导致完整模板的实例化。
根据工作草案 N3337,这两种行为都符合标准
[temp.inst]/6
If the overload resolution process can determine the correct function to call without instantiating a class template definition, it is unspecified whether that instantiation actually takes place.
template <class T> struct S {
operator int();
};
void f(int);
void f(S<int>&);
void f(S<float>);
void g(S<int>& sr) {
f(sr); // instantiation of S<int> allowed but not required
// instantiation of S<float> allowed but not required
};
[temp.inst]/7
If an implicit instantiation of a class template specialization is required and the template is declared but not defined, the program is ill-formed.
关于c++ - 为什么下面的代码会导致模板实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27481905/