[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Constraining a template class argument to a derived class of base

alan

11/5/2008 3:16:00 PM

Hello world,

I'm trying to figure out some way to constrain a template class
argument for a member function definition, such that the template
class argument must, totally, absolutely be a derived class of a
certain base class.

My current solution is:

class Base {
// etc..
};

class BaseHolder {
//etc
public:
template<class T>
T* make(void) {
/*This one!*/
Base* _check_derived_from_Base_ =
static_cast<Base*>((T*) 0);
return new(alloc(sizeof(T))) T();
}
};

It *seems* to work, but I think it's kind of hackish. Is there a
better, standards-defined way where I can specify that the class T in
the template should derive from "Base"?

Sincerely,
AmkG
3 Answers

Victor Bazarov

11/5/2008 3:50:00 PM

0

amkg wrote:
> Hello world,
>
> I'm trying to figure out some way to constrain a template class
> argument for a member function definition, such that the template
> class argument must, totally, absolutely be a derived class of a
> certain base class.
>
> My current solution is:
>
> class Base {
> // etc..
> };
>
> class BaseHolder {
> //etc
> public:
> template<class T>
> T* make(void) {
> /*This one!*/
> Base* _check_derived_from_Base_ =
> static_cast<Base*>((T*) 0);
> return new(alloc(sizeof(T))) T();
> }
> };
>
> It *seems* to work, but I think it's kind of hackish. Is there a
> better, standards-defined way where I can specify that the class T in
> the template should derive from "Base"?

Look in the archives for 'boost::enable_if', there will probably be an
example of determining whether the class is a base class or a derived
class of 'T'... Not sure if it's going to become standard (it isn't)
but Boost libraries are widely used nowadays (and most are free, IIRC).

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Michael DOUBEZ

11/5/2008 4:10:00 PM

0

amkg a écrit :
> Hello world,
>
> I'm trying to figure out some way to constrain a template class
> argument for a member function definition, such that the template
> class argument must, totally, absolutely be a derived class of a
> certain base class.
>
> My current solution is:
>
> class Base {
> // etc..
> };
>
> class BaseHolder {
> //etc
> public:
> template<class T>
> T* make(void) {
> /*This one!*/
> Base* _check_derived_from_Base_ =
> static_cast<Base*>((T*) 0);
> return new(alloc(sizeof(T))) T();
> }
> };
>
> It *seems* to work, but I think it's kind of hackish. Is there a
> better, standards-defined way where I can specify that the class T in
> the template should derive from "Base"?

Use boost static_assert and is_derived:
BOOST_STATIC_ASSERT(is_derived(T,Base));

If you don't want boost, the usual way to make the template
instantiation fail if a conversion cannot occur:

template <class T, class B>
struct assert_derived
{
//declare static constant to avoid T default construtible
static const T x;

//convert type to its pointer
template <class X>
static X* to_pointer(X const&);

//if can convert
static char convert_to_base(B const*);

//this fail if cannot convert to pointer
static const bool test=sizeof(convert_to_base(to_pointer(x)));
};


Then in your code:
assert_derived<T,Base>();

But the error code generated if far from meaningful.

--
Michael

alan

11/5/2008 10:23:00 PM

0

On Nov 6, 12:09 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> amkg a écrit :
>
>
>
> > Hello world,
>
> > I'm trying to figure out some way to constrain a template class
> > argument for a member function definition, such that the template
> > class argument must, totally, absolutely be a derived class of a
> > certain base class.
>
> > My current solution is:
>
> > class Base {
> > // etc..
> > };
>
> > class BaseHolder {
> > //etc
> > public:
> >     template<class T>
> >     T* make(void) {
> >         /*This one!*/
> >         Base* _check_derived_from_Base_ =
> >             static_cast<Base*>((T*) 0);
> >         return new(alloc(sizeof(T))) T();
> >     }
> > };
>
> > It *seems* to work, but I think it's kind of hackish.  Is there a
> > better, standards-defined way where I can specify that the class T in
> > the template should derive from "Base"?
>
> Use boost static_assert and is_derived:
> BOOST_STATIC_ASSERT(is_derived(T,Base));
>
> If you don't want boost, the usual way to make the template
> instantiation fail if a conversion cannot occur:
>
> template <class T, class B>
> struct assert_derived
> {
>      //declare static constant to avoid T default construtible
>      static const T x;
>
>      //convert type to its pointer
>      template <class X>
>          static X* to_pointer(X const&);
>
>      //if can convert
>      static char convert_to_base(B const*);
>
>      //this fail if cannot convert to pointer
>      static const bool test=sizeof(convert_to_base(to_pointer(x)));
>
> };
>
> Then in your code:
> assert_derived<T,Base>();
>
> But the error code generated if far from meaningful.
>
> --
> Michael

Thanks, I'll check out that template. Currently the hack I posted
gives a reasonable error in gcc - invalid static_cast from type ‘Bar*’
to type ‘Base*'. If the error code of that template is worse, I'll
stick with my hack I guess.