从另一个模板对象调用模板方法时的奇怪编译行为 [英] Strange compilation behaviour when calling a template method from another template object

查看:151
本文介绍了从另一个模板对象调用模板方法时的奇怪编译行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以解释为什么下面的c ++代码的行为不如预期:

  struct Object {
template< int i>
void foo(){}
};

template< int counter>
struct Container {
Object v [counter];

void test(){
//这样工作正常
Object a; a.foo 1();

//这也很好:
Object * b = new Object(); b - > foo 1();

//现在尝试与数组相同的事情:
v [0] = Object(); //很好(只是测试数组的访问)

#如果定义了BUG1
v [0] .foo< 1>(); //编译失败
#elif defined BUG2
(v [0])。foo< 1>(); //编译失败
#elif defined BUG3
auto& o = v [0];
o.foo< 1>(); // compilation failed
#else
Object& o = v [0];
o.foo< 1>(); // works
#endif
}
};

int main(){
Container< 10>容器;
}

上面的代码编译时没有标志。如果设置标志BUG1到BUG3中的一个,编译将失败,使用GCC 4.6或4.7和clang 3.2(这似乎表明它不是GCC错误)。



第21到29行在语义上完全相同(即调用Object数组的第一个元素的方法),但只有最后一个版本编译。当我尝试从一个模板对象调用一个模板方法时,这个问题似乎就出现了。



BUG1只是正常写调用的方法。 >

BUG2是相同的,但是在存在优先级问题(但不应该有任何问题)的情况下,数组访问受括号保护。



BUG3显示类型推断不工作(需要使用c ++ 11支持编译)。



最后一个版本工作正常,但我不明白为什么使用临时变量来存储引用来解决问题。



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

感谢

解决方案

您必须使用 as:

  v [0] .template foo& 

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

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



c $ c>关键字告诉编译器,后面是一个模板(在你的情况下, foo 确实是一个模板)。如果 foo 不是模板,则不需要模板关键字(实际上,这将是一个错误) 。



问题是 o.foo <1>()可以通过两种方式解析/解释:一个是你期望的(函数调用),另一种方式是:

 (o.foo) 1 //部分解析

foo 是一个成员数据(不是函数),并且将它与 1 进行比较。所以要告诉编译器< 不用于比较 o.foo 1 ,而是用于将模板参数 1 传递到函数模板,您需要使用 template 关键字。


Could someone explain why the following c++ code is not behaving as expected:

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

The code above compiles fine without flag. If one of the flag BUG1 to BUG3 is set, the compilation fails with either GCC 4.6 or 4.7 and with clang 3.2 (which seems to indicate it is not a GCC bug).

Lines 21 to 29 are doing exactly the same thing semantically (ie calling a method of the first element of the Object array), but only the last version compiles. The problem only seems to arise when I try to call a templated method from a template object.

BUG1 is just the "normal" way of writing the call.

BUG2 is the same thing, but the array access is protected by parenthesis in case there was a precedence problem (but there shouldn't be any).

BUG3 shows that type inference is not working either (needs to be compiled with c++11 support).

The last version works fine, but I don't understand why using a temporary variable to store the reference solves the problem.

I am curious to know why the other three are not valid.

Thanks

解决方案

You have to use template as:

v[0].template foo<1>();  

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

Because the declaration of v depends on the template argument, which makes v a dependent name.

Here the template keyword tells compiler that whatever follows is a template (in your case, foo is indeed a template). If foo is not a template, then the template keyword is not required (in fact, it would be an error).

The problem is that o.foo<1>() can be parsed/interpreted in two ways: one is just as you expect (a function call), the other way is this:

(o.foo) < 1  //partially parsed

that is, foo is a member data (not function), and you've comparing it with 1. So to tell the compiler that < is not used to compare o.foo with 1, rather it is used to pass template argument 1 to the function template, you're required to use template keyword.

这篇关于从另一个模板对象调用模板方法时的奇怪编译行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆