Template specialization for a list of types

M

mschellens

I this question some time ago, but didn't get a satisfying answer.
(Like including a file several times. Practical but ugly.)

The problem:
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?

Shouldn't there be something like:

template <> void B<T:[double,float]>( T)
{
// do something with float and double
}

or is there something alike already?

Regards,
Marc
 
L

Luca Risolia

The problem:
Lets say I have a template and five integer and two floating
types.
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?

#include <type_traits>

template <typename T>
void B_impl(T val, std::true_type) {/* integral version */}

template <typename T>
void B_impl(T val, std::false_type) { /* floating-point version */ }

template <typename T>
void B(T val) {
B_impl(val, std::is_integral<T>());
}
 
M

mschellens

#include <type_traits>



template <typename T>

void B_impl(T val, std::true_type) {/* integral version */}



template <typename T>

void B_impl(T val, std::false_type) { /* floating-point version */ }



template <typename T>

void B(T val) {

B_impl(val, std::is_integral<T>());

}

Thanks.
But this is still ugly, as one has to declare an ..._impl function for all functions in question.

I tried to use this idea as follows:

class FloatType {};
class IntType {};

class TraitsA
{
typedef IntType NumericType;
}
class TraitsB
{
typedef FloatType NumericType;
}

template< typename myTraits> class Data: public myTraits
{

void fun_impl( myTraits::NumericType);
void fun() { return fun_impl( myTraits::NumericType());}

};

template< typename MyTraits>
void Data<MyTraits>::fun_impl( FloatType)
{}

But g++ 4.6.1 said something like:
void Data<MyTraits>::fun_impl( FloatType) was not declared
candidate is void Data<MyTraits>::fun_impl( myTraits::NumericType)

Is this a limitation of g++, or do I miss something?

Anyway, I think my suggestion (s. a.: template <> void B<T:[double,float]>( T) {...}) would be much cleaner and universal (without any is_something<T> stuff).

Wouldn't such a construct be of common interest?

Regards,
Marc
 
L

Luca Risolia

But this is still ugly, as one has to declare an ..._impl function for all functions in question.

I don't quite understand what you mean by "all functions in question".
In your previous question there is one (member?) function "B" which you
apparently wanted to overload with different (pre-defined?) numeric types.
I tried to use this idea as follows:

class FloatType {};
class IntType {};

class TraitsA
{
typedef IntType NumericType;
}
class TraitsB
{
typedef FloatType NumericType;
}

template< typename myTraits> class Data: public myTraits
{

void fun_impl( myTraits::NumericType);
void fun() { return fun_impl( myTraits::NumericType());}

};

template< typename MyTraits>
void Data<MyTraits>::fun_impl( FloatType)
{}

But g++ 4.6.1 said something like:
void Data<MyTraits>::fun_impl( FloatType) was not declared
candidate is void Data<MyTraits>::fun_impl( myTraits::NumericType)

Is this a limitation of g++, or do I miss something?

Sorry, but from the above code it's really difficult to understand what
you exactly expect now.

Anyway, see if the following example can be of any help. It might be
close to what you want. I have tried to make it enough general so that
you can easily modify the essential parts according to your needs.

// define what a floating-point type is
template< class T >
struct is_float : std::integral_constant<
bool,
// std::is_same<FloatType, typename std::remove_cv<T>::type>::value ||
std::is_same said:

// a "default type" can be anything except a floating-point type
template< class T >
struct is_default : std::integral_constant<
bool,
!(is_float said:

// some shortcuts
template <typename T>
using Default = typename std::enable_if<is_default<T>::value>::type;

template <typename T>
using Float = typename std::enable_if<is_float<T>::value>::type;

// finally, your structure and member functions
struct A {
template <typename T>
Default<T> B1(T val) {
std::cout << "default\n";
}

template <typename T>
Float<T> B1(T val) {
std::cout << "floating-point\n";
}

// ...

template <typename T> Default<T> Bn(T val) {}
template <typename T> Float<T> Bn(T val) {}
};


int main() {
A o;
o.B1(1);
o.B1(IntType{});
o.B1(FloatType{});
o.B1((double)1.0);
o.B1((float)1.0);
}

/*
Output:
default
default
default
floating-point
floating-point
*/
Anyway, I think my suggestion (s. a.: template <> void B<T:[double,float]>( T) {...}) would be much cleaner and universal (without any is_something<T> stuff).

Wouldn't such a construct be of common interest?

Probably not..
 
8

88888 Dihedral

Luca Risoliaæ–¼ 2013å¹´3月22日星期五UTC+8上åˆ2時47分29秒寫é“:
But this is still ugly, as one has to declare an ..._impl function for all functions in question.



I don't quite understand what you mean by "all functions in question".

In your previous question there is one (member?) function "B" which you

apparently wanted to overload with different (pre-defined?) numeric types..


I tried to use this idea as follows:

class FloatType {};
class IntType {};

class TraitsA

typedef IntType NumericType;

class TraitsB

typedef FloatType NumericType;


template< typename myTraits> class Data: public myTraits


void fun_impl( myTraits::NumericType);
void fun() { return fun_impl( myTraits::NumericType());}



template< typename MyTraits>
void Data<MyTraits>::fun_impl( FloatType)


But g++ 4.6.1 said something like:
void Data<MyTraits>::fun_impl( FloatType) was not declared
candidate is void Data<MyTraits>::fun_impl( myTraits::NumericType)

Is this a limitation of g++, or do I miss something?



Sorry, but from the above code it's really difficult to understand what

you exactly expect now.



Anyway, see if the following example can be of any help. It might be

close to what you want. I have tried to make it enough general so that

you can easily modify the essential parts according to your needs.



// define what a floating-point type is

template< class T >

struct is_float : std::integral_constant<

bool,

// std::is_same<FloatType, typename std::remove_cv<T>::type>::value ||

std::is_same<float, typename std::remove_cv<T>::type>::value ||

std::is_same said:



// a "default type" can be anything except a floating-point type

template< class T >

struct is_default : std::integral_constant<

bool,

!(is_float said:



// some shortcuts

template <typename T>

using Default = typename std::enable_if<is_default<T>::value>::type;



template <typename T>

using Float = typename std::enable_if<is_float<T>::value>::type;



// finally, your structure and member functions

struct A {

template <typename T>

Default<T> B1(T val) {

std::cout << "default\n";

}



template <typename T>

Float<T> B1(T val) {

std::cout << "floating-point\n";

}



// ...



template <typename T> Default<T> Bn(T val) {}

template <typename T> Float<T> Bn(T val) {}

};





int main() {

A o;

o.B1(1);

o.B1(IntType{});

o.B1(FloatType{});

o.B1((double)1.0);

o.B1((float)1.0);

}



/*

Output:

default

default

default

floating-point

floating-point

*/


Anyway, I think my suggestion (s. a.: template <> void B<T:[double,float]>( T) {...}) would be much cleaner and universal (without any is_something<T> stuff).
Wouldn't such a construct be of common interest?



Probably not..

Closure is not defined clearly for all scalar types in c/ c++.
 
M

mschellens

But this is still ugly, as one has to declare an ..._impl function for all functions in question.



I don't quite understand what you mean by "all functions in question".

In your previous question there is one (member?) function "B" which you

apparently wanted to overload with different (pre-defined?) numeric types.


I tried to use this idea as follows:

class FloatType {};
class IntType {};

class TraitsA

typedef IntType NumericType;

class TraitsB

typedef FloatType NumericType;


template< typename myTraits> class Data: public myTraits


void fun_impl( myTraits::NumericType);
void fun() { return fun_impl( myTraits::NumericType());}



template< typename MyTraits>
void Data<MyTraits>::fun_impl( FloatType)


But g++ 4.6.1 said something like:
void Data<MyTraits>::fun_impl( FloatType) was not declared
candidate is void Data<MyTraits>::fun_impl( myTraits::NumericType)

Is this a limitation of g++, or do I miss something?



Sorry, but from the above code it's really difficult to understand what

you exactly expect now.



Anyway, see if the following example can be of any help. It might be

close to what you want. I have tried to make it enough general so that

you can easily modify the essential parts according to your needs.



// define what a floating-point type is

template< class T >

struct is_float : std::integral_constant<

bool,

// std::is_same<FloatType, typename std::remove_cv<T>::type>::value ||

std::is_same<float, typename std::remove_cv<T>::type>::value ||

std::is_same said:



// a "default type" can be anything except a floating-point type

template< class T >

struct is_default : std::integral_constant<

bool,

!(is_float said:



// some shortcuts

template <typename T>

using Default = typename std::enable_if<is_default<T>::value>::type;



template <typename T>

using Float = typename std::enable_if<is_float<T>::value>::type;



// finally, your structure and member functions

struct A {

template <typename T>

Default<T> B1(T val) {

std::cout << "default\n";

}



template <typename T>

Float<T> B1(T val) {

std::cout << "floating-point\n";

}



// ...



template <typename T> Default<T> Bn(T val) {}

template <typename T> Float<T> Bn(T val) {}

};





int main() {

A o;

o.B1(1);

o.B1(IntType{});

o.B1(FloatType{});

o.B1((double)1.0);

o.B1((float)1.0);

}



/*

Output:

default

default

default

floating-point

floating-point

*/


Anyway, I think my suggestion (s. a.: template <> void B<T:[double,float]>( T) {...}) would be much cleaner and universal (without any is_something<T> stuff).
Wouldn't such a construct be of common interest?



Probably not..

Thanks a lot Luca!
It took me some time to check it out, as I had to update g++ to 4.7 first (because of the use of "using").

And I could not use your example 1to1 but eventually it brought me on the right way:

One problem was, that my "struct A" is already templated. But the member functions have to be templates themselves, using SFINAE with the struct template parameter does not work.

And in reality I have four groups of types (Int, Float, Complex, Other). With some of the underlying types appearing in Int and Other (e. g. as int and hash value).

The solution was to define four structs in the template parameter of "struct A":

struct Traits1 // belonging to Group A
{
struct IfGroupA { typedef int type;}; // only one of the four has this typedef
struct IfGroupB { };
struct IfGroupC { };
struct IfGroupD { };
}
....
struct TraitsN // belonging to Group D
{
struct IfGroupA { };
struct IfGroupB { };
struct IfGroupC { };
struct IfGroupD { typedef int type;};
}

template <typename Traits>
struct A: public Traits
{
template <typename U = Traits>
typename U::IfGroupA::type B1() {}
....
template <typename U = Traits>
typename U::IfGroupD::type B1() {}
};
 
8

88888 Dihedral

mschellensæ–¼ 2013å¹´3月25日星期一UTC+8下åˆ5時57分56秒寫é“:
On 21/03/2013 15:13, mschellens wrote:
But this is still ugly, as one has to declare an ..._impl function for all functions in question.
I don't quite understand what you mean by "all functions in question".
In your previous question there is one (member?) function "B" which you
apparently wanted to overload with different (pre-defined?) numeric types.
I tried to use this idea as follows:
class FloatType {};
class IntType {};
class TraitsA
typedef IntType NumericType;
class TraitsB
typedef FloatType NumericType;
template< typename myTraits> class Data: public myTraits
void fun_impl( myTraits::NumericType);
void fun() { return fun_impl( myTraits::NumericType());}
template< typename MyTraits>
void Data<MyTraits>::fun_impl( FloatType)
But g++ 4.6.1 said something like:
void Data<MyTraits>::fun_impl( FloatType) was not declared
candidate is void Data<MyTraits>::fun_impl( myTraits::NumericType)
Is this a limitation of g++, or do I miss something?
Sorry, but from the above code it's really difficult to understand what
you exactly expect now.
Anyway, see if the following example can be of any help. It might be
close to what you want. I have tried to make it enough general so that
you can easily modify the essential parts according to your needs.
// define what a floating-point type is
template< class T >
struct is_float : std::integral_constant<

// std::is_same<FloatType, typename std::remove_cv<T>::type>::value ||
std::is_same<float, typename std::remove_cv<T>::type>::value ||
std::is_same<double, typename std::remove_cv<T>::type>::value
// a "default type" can be anything except a floating-point type
template< class T >
struct is_default : std::integral_constant<

!(is_float<T>::value) // default, change in case
// some shortcuts
template <typename T>
using Default = typename std::enable_if<is_default<T>::value>::type;
template <typename T>
using Float = typename std::enable_if<is_float<T>::value>::type;
// finally, your structure and member functions
struct A {
template <typename T>
Default<T> B1(T val) {
std::cout << "default\n";

template <typename T>
Float<T> B1(T val) {
std::cout << "floating-point\n";

// ...
template <typename T> Default<T> Bn(T val) {}
template <typename T> Float<T> Bn(T val) {}

int main() {
A o;
o.B1(IntType{});
o.B1(FloatType{});
o.B1((double)1.0);
o.B1((float)1.0);
floating-point
floating-point
Anyway, I think my suggestion (s. a.: template <> void B<T:[double,float]>( T) {...}) would be much cleaner and universal (without any is_something<T> stuff).
Wouldn't such a construct be of common interest?
Probably not..



Thanks a lot Luca!

It took me some time to check it out, as I had to update g++ to 4.7 first(because of the use of "using").



And I could not use your example 1to1 but eventually it brought me on theright way:



One problem was, that my "struct A" is already templated. But the member functions have to be templates themselves, using SFINAE with the struct template parameter does not work.



And in reality I have four groups of types (Int, Float, Complex, Other). With some of the underlying types appearing in Int and Other (e. g. as int and hash value).



The solution was to define four structs in the template parameter of "struct A":



struct Traits1 // belonging to Group A

{

struct IfGroupA { typedef int type;}; // only one of the four has this typedef

struct IfGroupB { };

struct IfGroupC { };

struct IfGroupD { };

}

...

struct TraitsN // belonging to Group D

{

struct IfGroupA { };

struct IfGroupB { };

struct IfGroupC { };

struct IfGroupD { typedef int type;};

}



template <typename Traits>

struct A: public Traits

{

template <typename U = Traits>

typename U::IfGroupA::type B1() {}

...

template <typename U = Traits>

typename U::IfGroupD::type B1() {}

};
I am not sure what you want to express.
A structure in c/c++ can be defined as a user defined type
to be used in functions or within structures.

But a structure defined type can not be subcalassed very
naturally in the C syntax.

In C++, java java script, c sharp....,
a different story began before year 2000.
 
S

Stefan Ram

A said:
But a structure defined type can not be subcalassed very
naturally in the C syntax.

In C:

struct class { int example; };
struct subclass { struct class base; int example; }

Functions in C can be written so as to accept a pointer to
an object of »subclass« as a pointer to an object of »class«
(by a kind of slicing).
 
M

mschellens

mschellensæ–¼ 2013å¹´3月25日星期一UTC+8下åˆ5時57分56秒寫é“:
On 21/03/2013 15:13, mschellens wrote:
But this is still ugly, as one has to declare an ..._impl function for all functions in question.
I don't quite understand what you mean by "all functions in question"..
In your previous question there is one (member?) function "B" which you
apparently wanted to overload with different (pre-defined?) numeric types.
I tried to use this idea as follows:
class FloatType {};
class IntType {};
class TraitsA
typedef IntType NumericType;
class TraitsB
typedef FloatType NumericType;
template< typename myTraits> class Data: public myTraits
void fun_impl( myTraits::NumericType);
void fun() { return fun_impl( myTraits::NumericType());}
template< typename MyTraits>
void Data<MyTraits>::fun_impl( FloatType)
But g++ 4.6.1 said something like:
void Data<MyTraits>::fun_impl( FloatType) was not declared
candidate is void Data<MyTraits>::fun_impl( myTraits::NumericType)
Is this a limitation of g++, or do I miss something?
Sorry, but from the above code it's really difficult to understand what
you exactly expect now.
Anyway, see if the following example can be of any help. It might be
close to what you want. I have tried to make it enough general so that
you can easily modify the essential parts according to your needs.
// define what a floating-point type is
template< class T >
struct is_float : std::integral_constant<
// std::is_same<FloatType, typename std::remove_cv<T>::type>::value ||
std::is_same<float, typename std::remove_cv<T>::type>::value ||
std::is_same<double, typename std::remove_cv<T>::type>::value
// a "default type" can be anything except a floating-point type
template< class T >
struct is_default : std::integral_constant<
!(is_float<T>::value) // default, change in case
// some shortcuts
template <typename T>
using Default = typename std::enable_if<is_default<T>::value>::type;
template <typename T>
using Float = typename std::enable_if<is_float<T>::value>::type;
// finally, your structure and member functions
struct A {
template <typename T>
Default<T> B1(T val) {
std::cout << "default\n";
template <typename T>
Float<T> B1(T val) {
std::cout << "floating-point\n";
template <typename T> Default<T> Bn(T val) {}
template <typename T> Float<T> Bn(T val) {}
int main() {
Anyway, I think my suggestion (s. a.: template <> void B<T:[double,float]>( T) {...}) would be much cleaner and universal (without any is_something<T> stuff).
Wouldn't such a construct be of common interest?
Probably not..
Thanks a lot Luca!
It took me some time to check it out, as I had to update g++ to 4.7 first (because of the use of "using").
And I could not use your example 1to1 but eventually it brought me on the right way:
One problem was, that my "struct A" is already templated. But the member functions have to be templates themselves, using SFINAE with the struct template parameter does not work.
And in reality I have four groups of types (Int, Float, Complex, Other).. With some of the underlying types appearing in Int and Other (e. g. as int and hash value).
The solution was to define four structs in the template parameter of "struct A":
struct Traits1 // belonging to Group A

struct IfGroupA { typedef int type;}; // only one of the four has this typedef
struct IfGroupB { };
struct IfGroupC { };
struct IfGroupD { };

struct TraitsN // belonging to Group D

struct IfGroupA { };
struct IfGroupB { };
struct IfGroupC { };
struct IfGroupD { typedef int type;};

template <typename Traits>
struct A: public Traits

template <typename U = Traits>
typename U::IfGroupA::type B1() {}

template <typename U = Traits>
typename U::IfGroupD::type B1() {}
};

I am not sure what you want to express.

.... but felt obliged to comment nevertheless.

A structure in c/c++ can be defined as a user defined type

to be used in functions or within structures.

Obviously you have not the faintest idea what we are talking about here.
Thanks to Luca I got it now (please google for SFINAE).

But a structure defined type can not be subcalassed very

naturally in the C syntax.
In C++, java java script, c sharp....,

a different story began before year 2000.

This is comp.lang.c++ .
C does not even support templates.

To say it in your words:
"I am not sure what you want to express."
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top