从另一个模板对象调用模板方法时出现奇怪的编译行为

Strange compilation behaviour when calling a template method from another template object

本文关键字:编译 另一个 对象 模板方法 调用      更新时间:2023-10-16

有人能解释一下为什么下面的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支持进行编译)。

上一个版本运行良好,但我不明白为什么使用临时变量来存储引用可以解决问题。

我很想知道为什么其他三个无效。

感谢

您必须将template用作:

v[0].template foo<1>();  
auto &o = v[0];
o.template foo<1>();     

因为v的声明依赖于模板参数,这使得v成为一个依赖名称。

这里template关键字告诉编译器,后面的任何内容都是模板(在您的情况下,foo实际上是一个模板)。如果foo不是模板,则不需要template关键字(事实上,这将是一个错误)。

问题是o.foo<1>()可以通过两种方式进行解析/解释:一种方式正如您所期望的(函数调用),另一种方式如下:

(o.foo) < 1  //partially parsed

也就是说,foo是一个成员数据(而不是函数),您已经将其与1进行了比较。因此,要告诉编译器<不是用来比较o.foo1的,而是用来将模板参数1传递给函数模板的,需要使用template关键字。

在模板中,表达式可以是依赖于类型的或依赖于值的

类型和表达式可能取决于模板参数的类型和/或值

在您的例子中,counter是一个模板参数,v的声明依赖于它,使v[0]成为一个依赖于

值的表达式。因此,名称foo是一个依赖名称,您必须通过说:来消除作为模板名称的歧义

v[0].template foo<1>();
相关文章: