p_a_c
p_a_c

Reputation: 285

Accessing inherited objects from class template

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

Answers (1)

quantdev
quantdev

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:

  • I'm not sure why gcc refuses using A::vec;, looks like a compiler bug to me (and note that using B<T>::A::vec; works).
  • Standard reference for template names lookup : § 14.6.3 and § 14.6.4

Upvotes: 2

Related Questions