简体   繁体   English

为什么以下代码会导致模板实例化?

[英]Why does the following code cause the template instantiation?

I have the following C++ code: 我有以下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;
}

If WORKS is defined as 0 (the struct template is defined) the code doesn't compile, because it tries to instantiate it at fFooBar(foobar); 如果WORKS被定义为0(定义了结构模板),则代码不会编译,因为它试图在fFooBar(foobar);实例化它fFooBar(foobar); and fails, because Bar is incomplete. 并且失败了,因为Bar不完整。

If WORKS is defined as 1 (the struct template is undefined) the code compiles. 如果WORKS定义为1(结构模板未定义),则代码将编译。

According to the standard, a template should not be instatiated, unless a complete type is required (which is not the case for const& ) or it would alter the semantics of the code (which again isn't the case, and againt, the same should happen if the template was undefined). 根据标准,模板不应该被实例化,除非需要一个完整的类型( const&不是这种情况)或者它会改变代码的语义(情况也不是这样,并且同样,相同)如果模板未定义,应该会发生)。

Also, it's weird that the program can be made to compile by removing information from the compilation unit. 而且,通过从编译单元中删除信息可以使程序编译,这很奇怪。 But the fact that MSVC, gcc, and clang all do the same makes me think there must be a reason behind this. MSVC,gcc和clang都这样做的事实让我觉得必须有这背后的理由。

When WORKS=0 , the program can be made to compile in Clang by qualifying the call to fFooBar with :: . WORKS=0 ,可以通过使用::限定对fFooBar的调用,使程序在Clang中编译。 The standard requires that name lookup behaves differently when an unqualified name is used in a function call. 该标准要求在函数调用中使用非限定名称时,名称查找的行为会有所不同。

[basic.lookup.argdep]/1 [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. 当函数调用(5.2.2)中的postfix-expression是非限定id时,可以搜索在通常的非限定查找(3.4.1)期间未考虑的其他名称空间,并在这些名称空间中搜索名称空间范围的朋友函数声明( 11.3)可能没有其他可见的。

Examining the (somewhat complex) rules for the Argument Dependent Lookup process suggests that it can only be implemented correctly in a way that would require the instantiation of template specialisations in the types of the arguments to the call. 检查Argument Dependent Lookup过程的(有点复杂的)规则表明它只能以需要在调用参数类型中实例化模板特化的方式正确实现。

[basic.lookup.argdep]/2 [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. 对于函数调用中的每个参数类型T,存在一组零个或多个关联的命名空间以及要考虑的一组零个或多个关联的类。 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; 如果T是类类型(包括联合),则其关联的类是:类本身; the class of which it is a member, if any; 它所属的成员,如果有的话; and its direct and indirect base classes. 及其直接和间接基类。

One interpretation of this is that a class is required to be complete if it is used in the type of an argument to an unqualified function call. 对此的一种解释是,如果在非限定函数调用的参数类型中使用类,则该类必须是完整的。 An alternative interpretation is that ADL should only cause instantiation of templates that are complete. 另一种解释是ADL应该只导致完整模板的实例化。

Either behaviour is compliant with the standard according to Working Draft N3337 根据N3337工作草案,这两种行为都符合标准

[temp.inst]/6 [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 [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. 如果需要隐式实例化类模板特化并且声明模板但未定义模板,则程序格式错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么这个乘法模板代码会导致溢出? - Why does this multiply template code cause overflow? 类模板的成员函数的显式实例化声明是否会导致类模板的实例化? - Does an explicit instantiation declaration of a member function of a class template cause instantiation of the class template? 为什么 C++ 模板实例化失败? - Why does a C++ template instantiation fail? 为什么我的可变参数模板实例化不起作用? - Why does my variadic template instantiation not work? 为什么显式模板实例化不会破坏 ODR? - Why does explicit template instantiation not break ODR? 为什么显式模板实例化的位置很重要 - Why does position of explicit template instantiation matter 模板的实例化可以导致二进制代码重复吗,编译器可以阻止吗? - Can instantiation of a template lead to a binary code duplication, does compiler prevent it? 为什么 const 会影响 gcc 中全局变量模板实例化的链接? - Why does const affect linkage of an instantiation of a global variable template in gcc? 为什么 extern 模板实例化不适用于仅移动类型? - Why does extern template instantiation not work on move-only types? typedef和using会导致模板实例化吗? - Do typedef and using cause a template instantiation?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM