Reputation: 285
I've been learning C++ templating and I've run across some weird behavior. Consider this class structure (stripped down from my original code):
class A {
public:
std::vector <int> vec;
};
template <typename T> class B : public A { };
template <typename T> class C : public B<T> {
public:
using A::vec;
int test() {
return vec[1]; // OK
}
int test2() {
return vec.size(); // error: 'class A' has no member named 'size'
}
};
When compiling, I get an error in test2
, saying that class A
has no member size
. But vec
should be a vector
object, not an instance of A
. Indeed, if I derive C
directly from A
instead of B<T>
, or remove the template from C
, it compiles fine.
Furthermore, if I add the following method to C
:
int test3() {
void ***v = vec; // error: cannot convert from
// 'std::vector<int,...>' to 'void***'
}
the compiler says it can't convert from a vector<int>
to void***
, so it seems to know the correct type for vec
. Am I making a mistake here, or is this possibly a bug in my compiler? I'm using an Apple version of g++ 4.2.1. Edit: also seems to occur in later versions of g++.
Thanks for your help!
Second edit: my compiler is happy if I use this->vec.size()
in test2
instead of relying on the using A::vec
declaration.
Upvotes: 5
Views: 197
Reputation: 23793
First, your code compiles with clang (see it here), and doesn't compile with gcc. I also got it to compile with VS2013.
Your original issue is related to how the compiler lookup names in templates.
The Standard § 14.6.2 :
Non-dependent names used in a template definition are found using the usual name lookup and bound at the point they are used.
Also the C++ FAQ has a good entry about it :
The compiler does not look in dependent base classes (like B) when looking up nondependent names (like vec).
Solution :
1. Use this->vec
(this is always implicitly dependent in a template)
int test2() {
return this->vec.size();
}
2. Use using B<T>::vec
3. Use B<T>
directly :
int test2() {
return B<T>::vec.size();
}
Notes:
using A::vec;
, looks like a compiler bug to me (and note that using B<T>::A::vec;
works).Upvotes: 2