By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,778 Members | 1,890 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,778 IT Pros & Developers. It's quick & easy.

Template specialization for a group of types

P: n/a
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

Jul 22 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
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;
}
Jul 22 '05 #2

P: n/a
On Thu, 20 Nov 2003 14:25:22 +0900, Marc Schellens
<m_*********@hotmail.com> wrote:
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
Jul 22 '05 #3

P: n/a
Marc Schellens wrote in news:3F**************@hotmail.com:
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,
member_ref_1< A< T >, T, &A< T >::B_int >,
member_ref_1< A< T >, T, &A< T >::B_float >

::type type
;
type::apply( this, arg );
}
};

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

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

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #4

P: n/a

"Patrick Kowalzick" <Pa***************@cern.ch> wrote in message
news:bp**********@sunnews.cern.ch...
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
Jul 22 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.