且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-11 19:12:33

您必须使用 as:

  v [0] .template foo& 

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

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



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



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

 (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.