2

Let's look at this simple code sample including a base class and a class derived from Base, which needs the address of a base class member in its constructor.

#include <vector>
#include <inttypes.h>
#include <stdio.h>

class Base
{
protected:
  std::vector<uint32_t> arr;
public:
  Base(std::vector<uint32_t> arr_in): arr(arr_in) {}
};

class Derived: public Base
{
private:
  uint32_t *parr;
public:
  Derived(std::vector<uint32_t> arr_in): Base(arr_in)
  {
    parr = &arr[0];
  }

  uint32_t *get_parr();
};

uint32_t *Derived::get_parr(void)
{
  return parr;
}

int main()
{
  std::vector<uint32_t> myarr(3, 1);
  Derived myderived(myarr);
  printf("myderived.myarr adress = %p", myderived.get_parr());
}

Since the constructor of the derived class calls the base class constructor first and only then executes its code block, the members of the base class can already be accessed. So everything works fine.

Now I change the code sample so that my two classes are templates.

#include <vector>
#include <inttypes.h>
#include <stdio.h>

template<typename T>
class Base
{
protected:
  std::vector<T> arr;
public:
  Base(std::vector<T> arr_in): arr(arr_in) {}
};

template<typename T>
class Derived: public Base<T>
{
private:
  T *parr;
public:
  Derived(std::vector<T> arr_in): Base<T>(arr_in)
  {
    parr = &arr[0];
  }

  T *get_parr();
};

template<typename T>
T *Derived<T>::get_parr(void)
{
  return parr;
}

int main()
{
  std::vector<uint32_t> myarr(3, 1);
  Derived<uint32_t> myderived(myarr);
  printf("myderived.myarr adress = %p", myderived.get_parr() );
}

But this second sample gives me the following error message upon compiling:

class_temp.cpp: In constructor ‘Derived<T>::Derived(std::vector<T>)’:
class_temp.cpp:23:13: error: ‘arr’ was not declared in this scope
     parr = &arr[0];

So why is it that in the second sample with template classes the derived class constructor doesn't know about the base class member? Or am I doing something wrong here?

Thank you.

1
  • 1
    I'm sure this is a duplicate but I can't find anything for some reason. Commented Sep 4, 2015 at 14:01

2 Answers 2

7

arr is a dependent name now. It depends on T. What if there is some T for which Base<T> is specialized to not have an arr? Specifically, from [temp.dep]:

In the definition of a class or class template, the scope of a dependent base class (14.6.2.1) is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

Base<T> is a dependent base class - it depends on the template parameter T, so its scope is not examined during unqualified name lookup. The way around this is to use qualified name lookup. That is, either the class name:

parr = &Base<T>::arr[0];

or just with this:

parr = &this->arr[0];
Sign up to request clarification or add additional context in comments.

2 Comments

Why parr = &Base<T>::arr[0]; works? Since the Derived is inheriting by class Derived: public Base<T>, if there is a specialization for Base<T> which can possibly make arr not exist, but why the same logic doesn't apply to &Base<T>::arr[0] ?
@Allanqunzi Because the scope of the dependent base class isn't looked up during unqualified lookup - if we do Base<T>::arr, we're doing qualified lookup. If arr doesn't exist, that would be a lookup failure - but we would find it if it did exist.
1

In the second case, the Base is a template and someone might add specializations for the template, all with different member variables. The compiler cannot know until it sees what T is.

There might also be a global arr that could fit. You can help the compiler by using this->arr[0] to indicate that it always is a member variable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.