Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Using" directive fails within template

I understand that the member names of a base-class template are hidden within the scope of a derived class, and therefore must be accessed using this->foo or Base<T>::foo. However, I recall that C++ also allows you to use the using keyword, which can come in handy in a derived-class function which frequently accesses a base-class variable. So, in order to avoid cluttering up the function with this-> everywhere, I'd like to use the using keyword.

I know I've done this before, but for whatever reason I can't get it to work now. I'm probably just doing something stupid, but the following code won't compile:

template <class T>
struct Base
{
   int x;
};

template <class T>
struct Derived : public Base<T>
{
   void dosomething()
   {
     using Base<T>::x; // gives compiler error
     x = 0;
   }
};

int main()
{
   Derived<int> d;
}

The error, (with GCC 4.3) is: error: ‘Base<T>’ is not a namespace

Why doesn't this work?

like image 933
Channel72 Avatar asked Dec 12 '22 17:12

Channel72


2 Answers

It doesn't work because C++ language has no such feature and never had. A using-declaration for a class member must be a member declaration. This means that you can only use in class scope, but never in local scope. This all has absolutely nothing to do with templates.

In other words, you can place your using-declaration into class scope

struct Derived : public Base<T> {
  ...
  using Base<T>::x;
  ...
};

but you can't have it inside a function.

Using-declarations for namespace members can be placed in local scope, but using-declarations for class members cannot be. This is why the error message complains about Base<T> not being a namespace.

like image 142
AnT Avatar answered Jan 02 '23 10:01

AnT


Outside class scope (if you are in a block etc), you can only name namespace members in a using declaration.

If you don't want to place that using declaration into the scope of Derived (which IMO is the favorable solution), your other option is to use a reference

int &x = this->x;
x = 0;

It should be noted that this is semantically different, because it

  • Forces a definition to exist for Base<T>::x, which might not be the case for static const data members
  • Forces Base<T>::x to be of type int& or be convertible to type int&.

Otherwise, if you want to avoid using this-> all again, I don't see other options.

like image 44
Johannes Schaub - litb Avatar answered Jan 02 '23 11:01

Johannes Schaub - litb