Automatic using for base class types

120 views
Skip to first unread message

razvan oprea

unread,
Nov 12, 2014, 6:52:15 AM11/12/14
to std-pr...@isocpp.org
Hello,

Consider the following examples:

template<typename A, typename B, typename C>
class BaseClass
{
public:
virtual void foo()
{
/*code*/
}
};
class SomeClass : public BaseClass < int, float, SomeOtherBaseClass >
{
public:
virtual void foo()
{
/*code before foo*/
BaseClass<int, float, SomeOtherBaseClass>::foo();
}
};

Problems:

For virtual functions if you have to write the base class in order to call the implementation.
This can be quite a pain if the base class is templated, or the name is very long.
Also if you change the base class you end up having to change all the places you used it.

Proposal:
Having using base_t defined in each class with the type of the base class:

using base_t = BaseClass<int,float,SomeOtherBaseClass>;

This will simplify writing base foo calls and because it's automatic all the problems described above will disappear.
One remaining problem is with multiple inheritance. For this i propose the use of base_t with a N being the index of the class used.

template <std::size_t N>
using base_t = typename std::tuple_element<N, std::tuple<BaseClass1, BaseClass2, BaseClass3>>::type;

Using base_t<N> is not very intuitive but i don't see how this can solved at this point.

Here is how it looks:

class SomeClass : public BaseClass<int,float,SomeOtherBaseClass>
{
public:
using base_t = BaseClass<int,float,SomeOtherBaseClass>; //this line could be defined automatically by the compiler saving the user the need to write redundant code.
virtual void foo()
{
/*code before foo*/
base_t::foo();//much easier to read and write
}
};


Alternative:

One alternative is to write it yourself for every class but when you change the base type you have to change the using definition also.




Tony V E

unread,
Nov 12, 2014, 10:16:11 AM11/12/14
to Andrzej Krzemieński

On Wed, Nov 12, 2014 at 6:52 AM, razvan oprea <razv...@gmail.com> wrote:
Hello,

Consider the following examples:

template<typename A, typename B, typename C>
class BaseClass
{
public:
virtual void foo()
{
/*code*/
}
};
class SomeClass : public BaseClass < int, float, SomeOtherBaseClass >
{
public:
virtual void foo()
{
/*code before foo*/
BaseClass<int, float, SomeOtherBaseClass>::foo();
}
};


I consider needing to call the base foo() an anti-pattern.  See, for example, http://www.gotw.ca/publications/mill18.htm

Having said that, there are other reasons to want base_t.  The usual argument against that is multiple inheritance, but you've shown a solution for that case.

Not sure whether it is worth being part of the language however - particularly if it required a new keyword or something.
If/When we get better reflection into the language, we could then probably add a library like std::base_tuple<SomeClass> that is the tuple of the bases.

Tony

Ville Voutilainen

unread,
Nov 12, 2014, 10:20:04 AM11/12/14
to std-pr...@isocpp.org
See the base class alias proposal referenced in
http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4225.html

Note that N4225 was rejected. Whether base class aliases would be accepted
is hard to say.

Bjorn Reese

unread,
Nov 12, 2014, 10:36:16 AM11/12/14
to std-pr...@isocpp.org
On 11/12/2014 04:16 PM, Tony V E wrote:

> Having said that, there are other reasons to want base_t. The usual

For instance in the base-from-member idiom.

razvan oprea

unread,
Nov 12, 2014, 11:01:18 AM11/12/14
to std-pr...@isocpp.org
Thanks for the feedback,

    I like the std::base_tuple<> idea and i think it would be easier to implement considering that there already exists std::underlying_type that relies on compiler extensions to work.

Razvan.

Ville Voutilainen

unread,
Nov 12, 2014, 11:06:04 AM11/12/14
to std-pr...@isocpp.org
For that sort of things, this proposal is in the pipeline
http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4113.pdf

Matthew Woehlke

unread,
Nov 12, 2014, 11:22:33 AM11/12/14
to std-pr...@isocpp.org
On 2014-11-12 06:52, razvan oprea wrote:
> template <std::size_t N>
> using base_t = typename std::tuple_element<N, std::tuple<BaseClass1,
> BaseClass2, BaseClass3>>::type;

I suggested almost exactly this a while back:
https://groups.google.com/a/isocpp.org/d/msg/std-proposals/zNvQQTKvoLQ/theH0edtsr4J

...although I also suggested being able to (optionally) specify what
entity's base type you are asking about.

--
Matthew

Nicola Gigante

unread,
Nov 12, 2014, 1:30:44 PM11/12/14
to std-pr...@isocpp.org
Hi

Another possibility would be to have an injected class name for the base classes.
This solves the problem for long template argument lists. Long class names are not
an issue for me..

Example:

template<typename A, typename B, typename C>
class BaseClass {
 // same as before...
};

class SomeClass : public BaseClase<int, float, SomeOtherClass>
{
public:
  virtual void foo() {
    BaseClass::foo();
  }
};

This breaks if one inherits from the same template instantiated with different types,
but in this convoluted case it might be enough to just complain about the ambiguity
and let the programmer specify the exact one needed.

What do you think about it?

Tony

Greetings,
Nicola

Matthew Greenwood

unread,
Nov 14, 2014, 7:31:58 AM11/14/14
to std-pr...@isocpp.org
I am new to this group so I may be completely off topic here.

Where I work we have created a pre-compel step that does something similar to what you want here.

How we currently define our inheritance chain for a class is something like this:

public Derived : public BaseClass1<int, char...> = _mybase1, private BaseClass2<std::string, double> = _mybase2
{
public:
   
virtual void foo()
   
{
        _mybase1
::foo();
        _mybase2
::foo();
   
}
}



this then gets converted to:

public Derived : public BaseClass1<int, char...>, private BaseClass2<std::string, double>
{
   
using _mybase1 = BaseClass1<int, char...>;
   
using _mybase2 = BaseClass2<std::string, double>;


public:
   
virtual void foo()
   
{
        _mybase1
::foo();
        _mybase2
::foo();
   
}
}


this gives us the simplicity of not having to make edits when we change a base class type.

I do agree having the compiler be able to support this would be very handy and reduce our dependancy on an external parser from the compiler.
Reply all
Reply to author
Forward
0 new messages