简体   繁体   中英

Is typedeffing templated base class to simplify the code a good practice?

I caught myself "inventing" this simple construct lately when working with many templated classes and deriving from them. I am not sure if it is common practice, or am I tying a rope around my neck.

template <typename T> class Base {};

template <typename T> class Derived : public Base<T>{
  typedef Base<T> Base;
};

I found it especially useful if the Base class has its own typedef s for some types. Eg:

template <typename T> class Base {
  typedef T Scalar;
  typedef Matrix<Scalar> Matrix;
};

Then it's easy to "import" types into the Derived . It saves re-typing the template signature. Eg:

template <typename T> class Derived : public Base<T>{
  typename Base<T>::Matrix yuck_yuck(); //that's what I am trying to simplify
  typedef typename Base<T> Base;
  typedef typename Base::Matrix Matrix;
  Matrix much_fun(); //looks way better
};

Also on of the big advantages is that, when you want to add another template parameter to the Base class. You don't have to go over a bunch of functions to change, just update the typedef . much_fun will have no problem if Base will be changed to Base<T,U> while yuck_yuck will need to have updated signatures (not sure if template parameter is formally included with the signature, so pardon me if I am making a formal error here, but I think it is).

Is this a good practice or am I playing with a gun next to my vital parts? It looks like it makes code more readable, and simplifies it, but maybe I am missing something that can backfire.

EDIT2: I got the working example. The Base class must be within its namespace or there will be conflicts with the same names within a scope, as the commenters pointed out. Below is the minimal example that embodies my real question.

namespace Fun {
template <typename T> class Base {
public:
  typedef T Scalar;
};
}

template <typename T> 
class Derived : public Fun::Base<T>{
public:
  typedef typename Fun::Base<T> Base;
  typedef typename Base::Scalar Scalar;
  typename Fun::Base<T>::Scalar yuck_yuck();
  Scalar much_fun();
};

#include <iostream>
using namespace std;

int main() {
    Derived<double> d;
    return 0;
}

With lots of stuff the code gets really bloated with typenames , and template parameters. But I already run into a trouble making up the example, by not placing Base in its own namespace. I wonder if there are any other caveats, that are actually killers to the idea.

I believe this is ill-formed, due to rule 2 of C++11 3.3.7/1

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S.

meaning that you can't use the name Base to refer to both the template and the typedef within the class scope. Certainly, my compiler won't accept it:

error: declaration of ‘typedef struct Base<T> Derived<T>::Base’ [-fpermissive]
error: changes meaning of ‘Base’ from ‘struct Base<T>’ [-fpermissive]

(NOTE: this refers to the simplified example originally posted, and doesn't cover the updated question where the base class name is in a different scope.)

I actually consider it a helpful (and good) practice if the typedef is not exposed public or protected:

// No template, not Base, to avoid that discussion
class Derive : public SomeBaseClass 
{
   private:
   typedef SomeBaseClass Base;

   public:
   typedef Base::T T;

   T f();
}; 

class MoreDerived : public Derived
{
   // Base is not accessible
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM