Topic: template< class D : public B >


Author: clerc@gla.ecoledoc.ibp.fr (Fabrice Clerc)
Date: 1995/05/20
Raw View
In article <3paqt3$ami@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
|> In article cj2@pheidippides.axion.bt.co.uk, pde@zoo.bt.co.uk (Paul D Evans) writes:
|> >Is there a reason why C++ does not admit the following:
|> >
|> >template< class D : public B > D goo( B parm ) { /* ... */ };
|> >
|> > ...
|> >
|> >Where template< class D : public B > is meant to express: given
|> >the class argument D, and a function argument B parm; check that
|> >the class statically bound to parm is an accessible base class of D.
|>
|> This is just one example of "constrained genericity". It would probably
|> be nice to have some syntax to express various constraints, such as
|> "must be publicly derived from B", or "must have an operator<",
|> or "must contain a typedef named X", or "must have a conversion
|> to type Y", or ...
|>
|> The issue is discussed in D&E. The short answer is that it seems too
|> complex to provide all the functionality with a special syntax. There
|> doesn't seem to be much reason to pick out just one or two categories
|> of constraints and ignore the others.
|>

Besides, we would need a way to express per-member constraints.
Could we afford to say: T used in std::list<T> must have operator< defined ?

Also, how would we express the fact that operator< could be defined as a member
of T or as a function outside the class ? That would mean writing 'code'
expressing the constraint. And that's exactly what we do when we write the
template members requiring constraints from their template arguments.

There remains one problem: knowledge of the constraints is scattered through
the code, which is not very 'user'-friendly.

Anyway, a little documentation never hurts...

|> ---
|> Steve Clamage, stephen.clamage@eng.sun.com
|>
|>

Fabrice Clerc
clerc@gla.ecoledoc.ibp.fr





Author: pde@zoo.bt.co.uk (Paul D Evans)
Date: 1995/05/16
Raw View
Is there a reason why C++ does not admit the following:

template< class D : public B > D goo( B parm ) { /* ... */ };

// ...

class T1 { /* ... */ };
class T2 : public  T1 { /* ... */ };
class T3 : public  T2 { /* ... */ };
class T4 : private T1 { /* ... */ };

// ...

T1 t1;
T2 t2;
T3 t3;
T4 t4;

// ...

t3 = goo< T3 >( t2 );  // OK
t3 = goo< T3 >( t1 );  // OK
t2 = goo< T2 >( t1 );  // OK
t4 = goo< T4 >( t1 );  // error - T1 not an accessible base class

Where template< class D : public B > is meant to express: given
the class argument D, and a function argument B parm; check that
the class statically bound to parm is an accessible base class of D.

This seems natural and easy to implement in C++.  An example that
springs to mind is dynamic_cast<> and templates that use it.

Or does the want of this suggest a bad design?

Thanks in advance,
---
                      ,')
-__ /\\                /|
  ||  \\   _           ||
 /||__||  < \, '\ /\\  ||        pde@zoo.bt.co.uk
 \||__||  /-||  || ||  ||
  ||  |, (( ||  || ||  ||               "Close this book at once,
_-||-_/   \/\\   \\/   |/   it's full of lies!"
  ||                   (_ _  The Book of Bokannon
                         -







Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1995/05/16
Raw View
In article cj2@pheidippides.axion.bt.co.uk, pde@zoo.bt.co.uk (Paul D Evans) writes:
>Is there a reason why C++ does not admit the following:
>
>template< class D : public B > D goo( B parm ) { /* ... */ };
>
> ...
>
>Where template< class D : public B > is meant to express: given
>the class argument D, and a function argument B parm; check that
>the class statically bound to parm is an accessible base class of D.

This is just one example of "constrained genericity". It would probably
be nice to have some syntax to express various constraints, such as
"must be publicly derived from B", or "must have an operator<",
or "must contain a typedef named X", or "must have a conversion
to type Y", or ...

The issue is discussed in D&E. The short answer is that it seems too
complex to provide all the functionality with a special syntax. There
doesn't seem to be much reason to pick out just one or two categories
of constraints and ignore the others.

You can enforce a constraint by creating dummy operations or types which
require the constraint, and get a compile-time error if the constraint
is not met. D&E (and I think C++PL2) has examples.

For your specific example, you could write

template< class D, class B > D goo(B parm)
{
 D result; // the value which will be returned
 static_cast<B*>(&result); // won't compile if constraint not met
 //... rest of function
 return result;
}

The dummy static cast won't generate any code, so there is no runtime penalty.
---
Steve Clamage, stephen.clamage@eng.sun.com