简体   繁体   中英

Two-phase lookup: is it possible to easily mix inheritence and templates

Intro: The C++ standards differentiates between symbols name which depend on template arguments, and names which don't, that's called two-phase name lookup (see here ). Non-dependant names are resolved as soon as possible when you define your template. On the other hand, dependant names are only resolved at template instanciation.

Example:

template<class T> struct Base {
    typedef T type;
    static const int n = 3;
    virtual int f() = 0;
    int f(int x) { return x * 2; }
};

// doesn't compile!
template<class T> struct Derived : Base<T> {
    type field;         // The compiler doesn't know Base<T>::type yet!
    int f() { return n; } // the compiler doesn't know n yet, and f(int) is maksed!
};

Currently, what I do is define Derived like this:

template<class T> struct Derived : Base<T> {
    typedef Base<T> Parent;
    typedef typename Parent::type type; // correct but
    using Parent::n;                    // boring, long
    using Parent::f;                    // and harder to maintain
    type field;
    int f() { return n; }
};

For me one of the main goal of object-oriented programming is reduce code duplication; this kind of defeat the purpose...

Question: is there another way do define Derived by using some syntax I don't know of or a smart trick? I'd love something like this:

template<class T> struct Derived : Base<T> {
    using Base<T>::*; // I promise I won't do strange specializations of Base<T>
    type field;
    int f() { return n; }
};

Edit Clarification: maybe I wasn't specific enough. Imagine you have a about ten typedefs / fields / functions in Base , and tens of derived classes with less than 5 lines of specific code for each. This means that most of the code will consist of repeated typedefs and using clauses, I know there's no way to totally avoid that, but I'm looking to minimize this repetitive code.

Thanks for any ideas making this easier to write and maintain!

T field;

That shouldn't be a problem; T is the template parameter itself, not a dependent name.

return n;

That is indeed a problem, since it's a dependent name and not known to be a member. The simplest solution is

return this->n;

Base<T>::n and Derived::n will also work, but I'd prefer not to duplicate the class names.

UPDATE

type field;

Unfortunately, there's no trick to access a dependent typename more simply than

typename Base<T>::type field;

Just hear me out a little

#include <string>
#include <iostream>

template<class T> struct Base {
    typedef T type;
    static const int n = 3;
    virtual int f() = 0;
    int f(int x) { return x * 2; }
};

// does compile
template< class T, template<typename> class Base = Base > 
struct Derived : Base<T> 
{
    typename Base<T>::type field; 
    int f() 
    {
        field = 200;
        return n;
    }
    int f(int x)
    {
        return Base<T>::f(x);
    }
};

int main()
{
    Derived<int> bss;
    std::cout << bss.f() << std::endl;
    std::cout << bss.f(50) << std::endl;
    std::cout << bss.field << std::endl;

    return 0;
}

This doesn't answer the question, but if you do allow specializations of Base (which... you really have to) then the behavior can get really weird.

Like consider this example...

template<class T> struct Base {
  typedef T type;
  static const int n = 3;
  virtual int f() = 0;
  int f(int x) { return x * 2; }
};

typedef float type;
static const int n = 5;

template<class T> struct Derived : Base<T> {
  type field;
  int f() { return n; }
};

It might not be intuitive, but at least the code is predictable. Derived::field is always a float and Derived::f() always returns 5.

If we somehow tricked the compiler into using every member of Base, then specializing Base in a weird way would cause Derived to behave in a very hard to determine way when it should be erroring out.

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