3

Two-phase lookup question: Is there a more synthetic way to write this code, i.e. avoiding all those using directives? Something like using CBase<T>; is what I would like, but it is not accepted.

#include <iostream>

template <typename T>
class CBase
{
protected:
    int a, b, c, d;   // many more...

public:
    CBase() {
        a = 123; c = 0;
    }
};


template <typename T>
class CDer : public CBase<T>
{
//  using CBase<T>;     // error, but this is what I would like
    using CBase<T>::a;
    using CBase<T>::b;
    //...

public:
    CDer() {
        std::cout << a << this->c;
    }
};


int main()
{
    CDer<int> cd;
}

In my real code there are many more member variables/functions, and I was wondering if it is possible to write shorter code in some way.
Of course, using the this->c syntax does not solve the problem...

Thank's!


gcc 4.1 MacOS X 10.6

Pietro
  • 12,086
  • 26
  • 100
  • 193
  • How about `std::cout << this->a;`? – kennytm Apr 02 '10 at 20:23
  • 1
    Or how about just `std::cout << a;` without any using directives? You have access to protected members of the superclass. – Alex Korban Apr 02 '10 at 20:30
  • 1
    @Alex: `error: ‘a’ was not declared in this scope`. – kennytm Apr 02 '10 at 20:34
  • A coworker of me had the same problem some weeks ago and was all upset about this behavior of C++ :) – Johannes Schaub - litb Apr 02 '10 at 20:53
  • If you have *that* many variables, of the same time (from what I'm gathering), what's wrong with an array? – GManNickG Apr 02 '10 at 20:55
  • @Alex: You cannot do it because these are template classes. – Pietro Apr 02 '10 at 21:51
  • @KennyTM: Yes, you can do that, but you still have to use the "this->" token... – Pietro Apr 02 '10 at 21:59
  • 1
    @GMan - Save the Unicorns: they are variables of different types. I could use a struct, but it would not bring any improvements. Regarding the unicorns, I'm afraid they are already extinct... ;-( – Pietro Apr 02 '10 at 22:04
  • Also, some people use class templates as some kind of "parameterized namespace" by wanting to parameterize the functions instead of the data. However, since the data types are not parameterized (they are int), you can put them all in a namespace and use function templates `namespace math { int a, b, c, d; template void f() { /* use a, b, ... */ } }` instead of defining derived classes, you just do `template void g() { using namespace math; /* use a, b, ... */ }` and are served well! – Johannes Schaub - litb Apr 02 '10 at 22:07
  • @Johannes: I think that is not my case. In your example a,b,c,... are static. – Pietro Apr 02 '10 at 22:29

2 Answers2

2

I reduced the testcase and then consider three options

template<typename T> struct Base { int a; };

Option 1

template<typename T> struct Der : Base<T> {
  void f() { 
    int &ra = Der::a;
    // now use ra
  }
}

Option 2

template<typename T> struct Der : Base<T> {
  void f() { 
    // use this->a instead
    // or Der::a
  }
}

Option 3

// use your using declarations
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Well, instead of: int &ra = Der::a; I would use a using directive. It is shorter and more explicit. I am starting to think there is no way to do it. I would have liked if this syntax would have been accepted: using CBase; – Pietro Apr 02 '10 at 22:13
  • @Pietro, since the compiler has no clue what names are made visible, it would render the whole rationale of not looking into the base for unqualified names for naught. The idea is that a simple `a` has no apparent relation to the `T` template parameter. And making it have a different meaning depending on what variables the base defines (even a private variable will change its meaning and make the access ill-formed!) isn't any good. Notice that the base class can be specialized for a given `T`. You have to explicitly declare that you *want* to depend on meanings that the base class defines. – Johannes Schaub - litb Apr 02 '10 at 22:23
  • you mean I had better surrender? After all it is just a stylistic detail. I think I won't kill myself for that. – Pietro Apr 02 '10 at 23:11
0

It doesn't look like most of those variables are parameterized. Does CBase use them all, or just a? If not, move them into a new non-template base of CDer.

Or, pack them all into a POD struct and then using CBase<T>::m_ints;.

High overhead solution: non-templated virtual base.

Not sure but worth a try: nest the definition of CDer inside CBase and then typedef it into namespace scope.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Yes, the variables in the real code are parametrized, and CBase would use them all. Moving the variables in a non template base class would solve the problem for CBase, but not for CDer. The POD still forces me to add a using directive for every variable. The virtual overhead is not affordable. – Pietro Apr 02 '10 at 23:00