c++ - 为什么下面的代码会导致模板实例化?

标签 c++ templates

我有以下 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/

相关文章:

c++ - 防止模板偏特化错误

c++ - 用于 Legendre 多项式的 gsl_sf_legendre_sphPlm_array() 替代方案

c++ - 恒定时间 "is bool array all 0' 秒?”

C++ - 在模板类之外但在头文件中定义成员函数

php - 如何制作一个php模板引擎?

javascript - 我无法输出 Handlebars 模板中的数据

c++ - 编译时模板参数计算

c++ - 使用 NULL 值初始化内存块是否等同于 free?

C++实现堆中值函数

c++ - 在 MPI 中对 cout 的 "atomic"调用