【问题标题】:Why does the following code cause the template instantiation?为什么下面的代码会导致模板实例化?
【发布时间】:2014-12-15 10:24:10
【问题描述】:

我有以下 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&amp; 不是这种情况)或者它会改变代码的语义(同样不是这种情况,同样,如果模板未定义,也会发生同样的情况。

此外,可以通过从编译单元中删除信息来编译程序,这很奇怪。但是 MSVC、gcc 和 clang 都做同样的事情让我觉得这背后一定有原因。

【问题讨论】:

  • ADL,我想。与stackoverflow.com/questions/25925551/… 类似的问题
  • @T.C. [temp.inst]/7?
  • @T.C.不过,这句话很含糊,在分析中不应该避免吗?
  • @Columbo 我也这么认为,但我的情况正好相反。我的程序在声明模板但未定义时工作。并且在定义时不编译。

标签: c++ templates


【解决方案1】:

WORKS=0 时,可以通过使用:: 限定对fFooBar 的调用,使程序在Clang 中编译。该标准要求在函数调用中使用非限定名称时,名称查找的行为会有所不同。

[basic.lookup.argdep]/1

当函数调用 (5.2.2) 中的后缀表达式是非限定 ID 时,不考虑其他命名空间 在通常的非限定查找(3.4.1)期间可能会被搜索,并且在这些命名空间中,命名空间范围 可能会找到不可见的友元函数声明 (11.3)。

检查参数依赖查找过程的(有些复杂的)规则表明,它只能以需要在调用的参数类型中实例化模板特化的方式正确实现。

[basic.lookup.argdep]/2

对于函数调用中的每个参数类型 T,都有一组零个或多个关联的命名空间和一个 要考虑的零个或多个相关类的集合。确定命名空间和类的集合 完全取决于函数参数的类型 [...]

  • 如果 T 是类类型(包括联合),则其关联的类是:类本身;它所属的类 成员,如果有的话;及其直接和间接基类。

对此的一种解释是,如果在非限定函数调用的参数类型中使用一个类,则它必须是完整的。另一种解释是 ADL 应该只导致完整模板的实例化。

任何一种行为都符合工作草案 N3337 的标准

[温度.inst]/6

如果重载解析过程可以在不实例化类的情况下确定要调用的正确函数 模板定义,未指定实例化是否实际发生。

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
};

[温度.inst]/7

如果需要类模板特化的隐式实例化并且模板已声明但未声明 已定义,程序格式不正确。

【讨论】:

  • 是的,我也发现了。我在回答自己,但我很高兴你回答,因为我不喜欢这种基于网络的自动色情。
  • 虽然我不确定语句 /7 会导致 WORKS=1 编译。它说如果需要专业化,那么该程序是不正确的。并没有真正说明不需要专业化时会发生什么(这是我的情况)。
  • it can only be implemented correctly in a way that would require the instantiation of template。好吧,我可以忍受它。但是为什么省略定义时它会起作用呢?
猜你喜欢
  • 1970-01-01
  • 2011-12-11
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 1970-01-01
  • 2015-12-12
  • 2019-08-31
  • 1970-01-01
相关资源
最近更新 更多