Template specialization for a group of types

M

Marc Schellens

I posted a similar question some time ago, but didn't get an
satisfying answer.

Lets say I have a template and five integer and two floating
types.

template <typename T> class A
{
A() {}
~A() {}

public:
void B( T);
};

// for all int
template <typename T> void B( T)
{
// do something with int (char, unsigned int ...)
}


template<> void B( float)
{
// do something with float
}
template<> void B( double)
{
// do something with double where the code looks the same as for float
}

How to avoid to replicate the code for float and double?
Or is it not possible?

Thanks,
marc
 
P

Patrick Kowalzick

Hi Marc,

I just wanted to post the same question :).

What I do: I use macros for that purpose, but I do not like it :-(. Please
see the code below:

So I would be happy to get a nicer solution as well.

Regards,
Patrick


// ***** CODE *****

struct A_1 {};
struct A_2 {};
struct B_1 {};
struct B_2 {};

// my class bar
template <typename> class bar;

// first GROUP of specializations of bar
#define create_class_A_bar(CA) \
template <> class bar<CA> \
{ \
typedef CA used_type; \
};

// class definitions Group A
create_class_A_bar(A_1);
create_class_A_bar(A_2);

// second GROUP of specializations of bar
#define create_class_B_bar(CB) \
template <> class bar<CB> \
{ \
typedef CB used_type; \
};

// class definitions Group A
create_class_B_bar(B_1);
create_class_B_bar(B_2);

// some usage
int main()
{
bar<A_1>;
bar<A_2>;
bar<B_1>;
bar<B_2>;

return 0;
}
 
T

tom_usenet

I posted a similar question some time ago, but didn't get an
satisfying answer.

Lets say I have a template and five integer and two floating
types.

template <typename T> class A
{
A() {}
~A() {}

public:
void B( T);
};

// for all int
template <typename T> void B( T)
{
// do something with int (char, unsigned int ...)
}


template<> void B( float)
{
// do something with float
}
template<> void B( double)
{
// do something with double where the code looks the same as for float
}

How to avoid to replicate the code for float and double?
Or is it not possible?

It is possible:

/* If you can't use boost
template <class T>
struct is_integral
{
static bool const value = false;
};

template<> struct is_integral<int>{static bool const value = true;};
template<> struct is_integral<unsigned>{static bool const value =
true;};
template<> struct is_integral<short>{static bool const value = true;};
template<> struct is_integral<unsigned short>{static bool const value
= true;};
template<> struct is_integral<char>{static bool const value = true;};
template<> struct is_integral<unsigned char>{static bool const value =
true;};
template<> struct is_integral<signed char>{static bool const value =
true;};
template<> struct is_integral<long>{static bool const value = true;};
template<> struct is_integral<unsigned long>{static bool const value =
true;};

//need const/volatile versions, etc. too!
//what about bool?
*/
// The boost version:
#include <boost/type_traits.hpp>
using boost::is_integral;

template <typename T> class A
{
public:
A() {}
~A() {}
void B(T);
};

#include <iostream>

template <bool B>
struct B_impl
{
template <class T>
static void impl(T t)
{
std::cout << "Integer version\n";
}
};
template <>
struct B_impl<false>
{
template <class T>
static void impl(T t)
{
std::cout << "Float version\n";
}
};
// for all int
template <typename T> void A<T>::B(T t)
{
B_impl<is_integral<T>::value>::impl(t);
}

int main()
{
A<short> a;
a.B(5);

A<double> b;
b.B(7.5);
}

Tom
 
R

Rob Williscroft

Marc Schellens wrote in
I posted a similar question some time ago, but didn't get an
satisfying answer.

Lets say I have a template and five integer and two floating
types.

template <typename T> class A
{
A() {}
~A() {}

public:
void B( T);
};

// for all int
template <typename T> void B( T)
{
// do something with int (char, unsigned int ...)
}


template<> void B( float)
{
// do something with float
}
template<> void B( double)
{
// do something with double where the code looks the same as for float
}

How to avoid to replicate the code for float and double?
Or is it not possible?

An alternative is a simple refactor:

template < typename T> A< T >::B( T arg )
{
// int version.
}

/* New (?private?) member
template < typename T> A< T >::B_float( T arg )
{
// int version.
}

template <> inline A< float >::B( float arg )
{
B_float( arg );
}

template <> inline A< double >::B( double arg )
{
B_float( arg );
}

If you like typing (or you *need* to generalize),

#include <iostream>
#include <ostream>
#include <limits>

#if 0 /* boost is preferable if you have it */
#include "boost/mpl/if.hpp"
using boost::mpl::if_c;
#else
template < bool True, typename TrueT, typename FalseT >
struct if_c
{
typedef TrueT type;
};
template < typename TrueT, typename FalseT >
struct if_c< false, TrueT, FalseT >
{
typedef FalseT type;
};
#endif

template < typename T, typename Arg, void (T::*F)( Arg ) >
struct member_ref_1
{
static void apply( T *that, Arg arg )
{
(that->*F)( arg );
}
};


template < typename T > struct A
{
void B_int( T arg ) { std::cerr << "int\n"; }
void B_float( T arg ) { std::cerr << "float\n"; }

void B( T arg )
{
typedef
if_c<
std::numeric_limits< T >::is_integer,
::type type
;
type::apply( this, arg );
}
};

int main()
{
A< int > aint;
aint.B( 0 );

A< double > adouble;
adouble.B( 0.0 );
}

Rob.
 
C

Chris Theis

Patrick Kowalzick said:
Hi Marc,

I just wanted to post the same question :).

What I do: I use macros for that purpose, but I do not like it :-(. Please
see the code below:

So I would be happy to get a nicer solution as well.

Regards,
Patrick


// ***** CODE *****

struct A_1 {};
struct A_2 {};
struct B_1 {};
struct B_2 {};

// my class bar
template <typename> class bar;

// first GROUP of specializations of bar
#define create_class_A_bar(CA) \
template <> class bar<CA> \
{ \
typedef CA used_type; \
};

// class definitions Group A
create_class_A_bar(A_1);
create_class_A_bar(A_2);

// second GROUP of specializations of bar
#define create_class_B_bar(CB) \
template <> class bar<CB> \
{ \
typedef CB used_type; \
};

// class definitions Group A
create_class_B_bar(B_1);
create_class_B_bar(B_2);

// some usage
int main()
{
bar<A_1>;
bar<A_2>;
bar<B_1>;
bar<B_2>;

return 0;
}


One possible solution would be the usage of type lists although, as
discussed with Patrick, IMHO would be simply too much overhead for such a
problem. The standard stream library has the same problem to cope with
(overloading of op << for all the different POD types) and there you see
that it's done "by hand". In lack of better ideas I'd personally stick with
the macros. Sure, the statement "macros are evil" is more or less true but
there are exceptions.

Regards
Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top