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
templateas:Because the declaration of
vdepends on the template argument, which makesva dependent name.Here the
templatekeyword tells compiler that whatever follows is a template (in your case,foois indeed a template). Iffoois not a template, then thetemplatekeyword 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:that is,
foois a member data (not function), and you’ve comparing it with1. So to tell the compiler that<is not used to compareo.foowith1, rather it is used to pass template argument1to the function template, you’re required to usetemplatekeyword.