【发布时间】:2012-12-01 15:41:57
【问题描述】:
有人能解释一下为什么下面的 c++ 代码没有按预期运行吗:
struct Object {
template< int i >
void foo(){ }
};
template<int counter>
struct Container {
Object v[counter];
void test(){
// this works as expected
Object a; a.foo<1>();
// This works as well:
Object *b = new Object(); b->foo<1>();
// now try the same thing with the array:
v[0] = Object(); // that's fine (just testing access to the array)
# if defined BUG1
v[0].foo<1>(); // compilation fails
# elif defined BUG2
(v[0]).foo<1>(); // compilation fails
# elif defined BUG3
auto &o = v[0];
o.foo<1>(); // compilation fails
# else
Object &o = v[0];
o.foo<1>(); // works
# endif
}
};
int main(){
Container<10> container;
}
上面的代码在没有标志的情况下编译得很好。如果设置了标志 BUG1 到 BUG3 中的一个,则使用 GCC 4.6 或 4.7 和 clang 3.2 编译会失败(这似乎表明它不是 GCC 错误)。
第 21 到 29 行在语义上做了完全相同的事情(即调用 Object 数组的第一个元素的方法),但只有最后一个版本可以编译。只有当我尝试从模板对象调用模板化方法时,才会出现问题。
BUG1 只是编写调用的“正常”方式。
BUG2 也是一样,但数组访问受括号保护,以防出现优先级问题(但不应该有)。
BUG3 显示类型推断也不起作用(需要使用 c++11 支持编译)。
上一个版本运行良好,但我不明白为什么使用临时变量来存储引用可以解决问题。
我很想知道为什么其他三个无效。
谢谢
【问题讨论】:
-
试试
v[0].template foo<1>();。 -
@KerrekSB:有趣的是为什么这是必要的。看起来 v[0] 不是依赖表达式,所以编译器在解析模板时应该能够解析它的类型。
-
@VaughnCato:我还没有测试过,我也不确定。这只是一个建议......毕竟,OP 并没有告诉我们错误是什么,而且只有这么多猜测可以做。
-
啊,看起来
v是一个依赖于值的名称(参见14.6.2)。 -
@Thibaut:是的,我认为这实际上是一个非常简单的论点:使用
auto,类型被推断出来,它被推断为依赖类型(即Object[counter]()[0]的类型)。在另一个分支上,您明确地说Object &,所以没有任何推论。如果您更改了Object类型的名称,auto代码将继续工作,而显式代码将中断。明确表示你知道编译器不知道如何使用模板。
标签: c++ templates compilation compiler-errors