Convenient typedef of base classes

5 views
Skip to first unread message

Dragan Milenkovic

unread,
Dec 2, 2008, 10:34:29 AM12/2/08
to
Was something like this ever suggested?
(I'm expecting the answer - it's already in C++0x :-)

template <typename A, typename B>
class Bar : public Foo<typename std::remove_const<A>::type, B> = Base {
...
};

to be equivalent to:

template <typename A, typename B>
class Bar : public Foo<typename std::remove_const<A>::type, B> {
typedef Foo<typename std::remove_const<A>::type, B> Base;
...
};

--
Best regards,
Dragan

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Seungbeom Kim

unread,
Dec 3, 2008, 11:12:10 AM12/3/08
to
Dragan Milenkovic wrote:
> Was something like this ever suggested?
> (I'm expecting the answer - it's already in C++0x :-)
>
> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> = Base {
> ...
> };
>
> to be equivalent to:
>
> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> {
> typedef Foo<typename std::remove_const<A>::type, B> Base;
> ...
> };
>

Yes, many times, including, but not limited to:

http://groups.google.com/group/comp.std.c++/msg/32222e1c62a5fe72
http://groups.google.com/group/comp.std.c++/msg/12eeaba4410ade3e

The second proposes something that looks exactly like your proposal.

I haven't heard that it's already in C++0x, though I wish it were.
I can't think of any reason it shouldn't be, except that nobody has
written and submitted a formal proposal yet.

--
Seungbeom Kim

Christof Meerwald

unread,
Dec 3, 2008, 11:22:08 AM12/3/08
to
On Tue, 2 Dec 2008 09:34:29 CST, Dragan Milenkovic wrote:
[...]

> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> {
> typedef Foo<typename std::remove_const<A>::type, B> Base;
> ...
> };

Note that with TC1, you are able to refer to the base class just by the
class name (Foo in this case) instead of having to repeat all template
arguments.

see http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#176


Christof

--
http://cmeerw.org sip:cmeerw at cmeerw.org
mailto:cmeerw at cmeerw.org xmpp:cmeerw at cmeerw.org

Roman.Pe...@gmail.com

unread,
Dec 3, 2008, 11:39:42 AM12/3/08
to
On 2 Dec, 16:34, Dragan Milenkovic <dra...@plusplus.rs> wrote:
> Was something like this ever suggested?
> (I'm expecting the answer - it's already in C++0x :-)
>
> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> = Base {
> ...
>
> };
>
> to be equivalent to:
>
> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> {
> typedef Foo<typename std::remove_const<A>::type, B> Base;
> ...
>
> };

Thanks to injected names, base class name is already available by the
short name Foo.

template <typename A, typename B>

class Bar : public Foo<typename std::remove_const<A>::type, B> {
// Foo is a synonym for Foo<typename std::remove_const<A>::type, B>.
Foo foo;
};

// Foo is even accessible from outside of the class.
Bar<int, int>::Foo foo;

Note that GCC can't compile this code due to a compiler bug.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37350
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9937

Roman Perepelitsa.

--

Hak...@gmail.com

unread,
Dec 4, 2008, 2:01:06 PM12/4/08
to
On Dec 2, 10:34 am, Dragan Milenkovic <dra...@plusplus.rs> wrote:
> Was something like this ever suggested?
> (I'm expecting the answer - it's already in C++0x :-)
>
> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> = Base {
> ...
>
> };
>
> to be equivalent to:
>
> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> {
> typedef Foo<typename std::remove_const<A>::type, B> Base;
> ...
>
> };

I think this might lead to disorderly code, especially in cases of
multiple inheritance where you'd have base1 and base2.

template <typename A, typename B>
class Bar : public Foo<typename std::remove_const<A>::type, B> = Base
{

// Typedef list.
typedef type-expression Type1;
typedef type-expression Type2;
typedef type-expression Type3;

void f( Base x );
};

If I were reading this code, I would see Base and, not recognizing the
type and assuming it's a typedef, I'd look at the typedef list. Not
seeing it, I would be lost. Furthermore, I would not be in the habit
of looking at the inheritance line for typedef info and it may not be
intuitive when first I see it. It also further clutters the class
definition. However...

template <typename A, typename B>

class Bar : public typedef Bar::Base {

// Typedef list.
typedef type-expression Type1;
typedef type-expression Type2;
typedef type-expression Type3;


typedef Foo<typename std::remove_const<A>::type, B> Base;

void f( Base x );
};

would be more appealing to me. Here, Bar:: signifies that the typedef
is internal and it's intuitive because I already understand scope
resolution, so this introduced no new logic to me.

Or perhaps

template <typename A, typename B>

// Typedef list.
typedef type-expression Type1;
typedef type-expression Type2;
typedef type-expression Type3;


typedef Foo<typename std::remove_const<A>::type, B> Base;

class Bar : public Base {

void f( Base x );
};

Although, this is not preferable to me as there is a lot of
information about the class presented before I've even read its name!
And, this would be an odd and unconventional place to hide the typedef
list.

Then again, I've wanted to do this for a long time:

template< class T, class Y >
{
typedef T int_type;
typedef Y int_type2;
void f( int_type, int_type2) {}
void g( int_type, int_type2) {}

typedef Y float_type;
void h( int_type, float_type) {}
}


--

Dragan Milenkovic

unread,
Dec 4, 2008, 8:18:38 PM12/4/08
to
Hak...@gmail.com wrote:
> On Dec 2, 10:34 am, Dragan Milenkovic <dra...@plusplus.rs> wrote:
>> Was something like this ever suggested?
>> (I'm expecting the answer - it's already in C++0x :-)
>>
>> template <typename A, typename B>
>> class Bar : public Foo<typename std::remove_const<A>::type, B> = Base {
>> ...
>>
>> };
>>
>> to be equivalent to:
>>
>> template <typename A, typename B>
>> class Bar : public Foo<typename std::remove_const<A>::type, B> {
>> typedef Foo<typename std::remove_const<A>::type, B> Base;
>> ...
>>
>> };
>
> I think this might lead to disorderly code, especially in cases of
> multiple inheritance where you'd have base1 and base2.

The programmer may choose to make a typedef or may choose not to.
"Base1" and "Base2" are very poor choices. How about "Base"
and "Interface", or whatever is the meaning of that inheritance.
Maybe "Helper_base", "Adaptee" or even "Wrapped_stuff".


> template <typename A, typename B>
> class Bar : public Foo<typename std::remove_const<A>::type, B> = Base
> {
>
> // Typedef list.
> typedef type-expression Type1;
> typedef type-expression Type2;
> typedef type-expression Type3;
>
> void f( Base x );
> };
>
> If I were reading this code, I would see Base and, not recognizing the
> type and assuming it's a typedef, I'd look at the typedef list. Not
> seeing it, I would be lost. Furthermore, I would not be in the habit
> of looking at the inheritance line for typedef info and it may not be
> intuitive when first I see it. It also further clutters the class
> definition. However...

Maybe a real world example where you use a base class in function
declaration would help me understand why this bothers you. I usually
use it in implementation, not interface.


> template <typename A, typename B>
> class Bar : public typedef Bar::Base {
>
> // Typedef list.
> typedef type-expression Type1;
> typedef type-expression Type2;
> typedef type-expression Type3;
> typedef Foo<typename std::remove_const<A>::type, B> Base;
>
> void f( Base x );
> };
>
> would be more appealing to me. Here, Bar:: signifies that the typedef
> is internal and it's intuitive because I already understand scope
> resolution, so this introduced no new logic to me.

It could work for private/protected inheritance. But IMHO, when
working with an "is-a" relationship, it's very messy to understand
that Bar is-a Foo here. And this relationship is quite important,
wouldn't you agree? More important than making a convenient name
for it. Also, I guess this would also be very complicated to implement.


>
> Or perhaps
>
> template <typename A, typename B>
> // Typedef list.
> typedef type-expression Type1;
> typedef type-expression Type2;
> typedef type-expression Type3;
> typedef Foo<typename std::remove_const<A>::type, B> Base;
> class Bar : public Base {
>
> void f( Base x );
> };
>
> Although, this is not preferable to me as there is a lot of
> information about the class presented before I've even read its name!
> And, this would be an odd and unconventional place to hide the typedef
> list.

Heh... You don't prefer it, yet to me, this one looks better than
former ones.


Ok, if in
/class Bar : public Foo<typename std::remove_const<A>::type, B> = Base/
it's too hard to find the word "Base", and also because "=" should
assign rhs to lhs not vice-versa, maybe this would do:

class Bar : public Base = Foo<typename std::remove_const<A>::type, B>

but then again, I'd like to bring Foo in the first plan because
it is more important than the fact we made a typedef... so...

class Bar : public Foo<typename std::remove_const<A>::type, B> -> Base


Any thoughts?

--
Best regards,
Dragan

Hak...@gmail.com

unread,
Dec 5, 2008, 9:34:24 PM12/5/08
to
On Dec 4, 8:18 pm, Dragan Milenkovic <dra...@plusplus.rs> wrote:
> > template <typename A, typename B>
> > class Bar : public Foo<typename std::remove_const<A>::type, B> = Base
> > {
>
> > // Typedef list.
> > typedef type-expression Type1;
> > typedef type-expression Type2;
> > typedef type-expression Type3;
>
> > void f( Base x );
> > };
>
> > If I were reading this code, I would see Base and, not recognizing the
> > type and assuming it's a typedef, I'd look at the typedef list. Not
> > seeing it, I would be lost. Furthermore, I would not be in the habit
> > of looking at the inheritance line for typedef info and it may not be
> > intuitive when first I see it. It also further clutters the class
> > definition. However...
>
> Maybe a real world example where you use a base class in function
> declaration would help me understand why this bothers you. I usually
> use it in implementation, not interface.

I don't know how this code would work in the real world as this is a
problem I'm struggling with right now, but here's a go at it:

template<class Char, class Traits>
class Logger : public Otype = std::ostream<Char, Traits>
{
// Typedef list.
typedef Char char_type;
typedef Traits traits_type;

Logger();
Logger( const Otype& x );
};

Does this example show my point better? I will look for Otype in the
typedef list and not find it.

However, I can see how I might be trained to look in the definition
seeing how I can gesture that Otype will be the parent of the Logger,
just going by logic. Still, I shouldn't have to THINK about it, the
code should be more self-explanatory.

Also, there is some inconsistency. To write the parent, I use Char and
Traits, but then typedef them. I'd rather be able to JUST use the
typedefs and abstract the idea of Char and Traits as soon as possible.

> > template <typename A, typename B>
> > class Bar : public typedef Bar::Base {
>
> > // Typedef list.
> > typedef type-expression Type1;
> > typedef type-expression Type2;
> > typedef type-expression Type3;
> > typedef Foo<typename std::remove_const<A>::type, B> Base;
>
> > void f( Base x );
> > };
>
> > would be more appealing to me. Here, Bar:: signifies that the typedef
> > is internal and it's intuitive because I already understand scope
> > resolution, so this introduced no new logic to me.
>
> It could work for private/protected inheritance. But IMHO, when
> working with an "is-a" relationship, it's very messy to understand
> that Bar is-a Foo here. And this relationship is quite important,
> wouldn't you agree? More important than making a convenient name
> for it.

You would see the typename Bar::Base (I know I wrote typedef, but I
should have wrote typename) and know that you'd have to look inside
the class to know what Base is. In my example, it'd be Logger::Otype
and you'd say "Oh! Logger is derived from an Otype: probably an
ostream or something." You'd then look in the class to confirm this
and hopefully, nothing surprising would appear.

> Also, I guess this would also be very complicated to implement.

Hmm... I don't really know how compilers work (yet), but I'd guess
they'd just have to do one hell of a look-ahead. Is this something
incredibly hard for compilers?

> Ok, if in
> /class Bar : public Foo<typename std::remove_const<A>::type, B> = Base/
> it's too hard to find the word "Base", and also because "=" should
> assign rhs to lhs not vice-versa, maybe this would do:
>
> class Bar : public Base = Foo<typename std::remove_const<A>::type, B>

Agreed.


> but then again, I'd like to bring Foo in the first plan because
> it is more important than the fact we made a typedef... so...
>
> class Bar : public Foo<typename std::remove_const<A>::type, B> -> Base
>
> Any thoughts?

Well, that doesn't exactly introduce new logic since "unified function
syntax" will use similar logic (if I'm not mistaken), but I can't say
I entirely like "unified function syntax" as THAT introduces new
logic. I agree what Base actually means is more important, but I don't
think Base = makes it any harder to find out.


--

Vidar Hasfjord

unread,
Dec 6, 2008, 3:59:51 PM12/6/08
to
On Dec 5, 1:18 am, Dragan Milenkovic <dra...@plusplus.rs> wrote:
> class Bar : public Foo<typename std::remove_const<A>::type, B> -> Base
>
> Any thoughts?

I don't fancy the extra syntax. Having built-in metadata seems a
better alternative. E.g.:

struct D : A, B, virtual C {
typedef this_meta::type this_type;
typedef this_meta::base <0>::type first_base;
typedef this_meta::base <1>::type second_base;
const bool has_virtual_third_base =
this_meta::base <2>::is_virtual;
}

Regards,
Vidar Hasfjord


--

Reply all
Reply to author
Forward
0 new messages