473,379 Members | 1,257 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,379 software developers and data experts.

Template function specialization/overloading

I am facing the following scenario: I have a class 'A', that implements
some concept C -- but we know this, not because A inherits from a
virtual class 'C', but only because a trait tell us so:

class A {};

template <typename T>
struct Is_C
{
static const bool value = false;
};

template <>
struct Is_C<A>
{
static const bool value = true;
};
What I would like to do is, given an instance 'a' of A, call a function
'foo(a)' that would have specific code for class A -- and have default
code for other classes.

The following

template < typename T >
void foo(T t)
{
if (Is_C<T>::value)
{
/* ... */
}
else
{
/* ... */
}
}

would work, but then, it is not extensible to another trait 'Is_D'
unless I modify the function foo. Ideally I would have a function foo
for the general case (corresponding to the 'else') and as many
functions foo for all the different tests, but I am not sure how to do
that. I would like to use the boost::enable_if, but if I use function
overloading, I need to have a disable_if in my 'general case' foo for
each 'specialized' foo:

// General case
template < typename T >
typename disable_if<Is_C<T> >::type // This has to be modified if
another foo is added
foo(T t)
{
/* ... */
}

// Specialization for concept C
template < typename T >
typename enable_if<Is_C<T> >::type
foo(T t)
{
/* ... */
}

I would really appreciate any suggestion for this problem.

Thanks

B.

Jul 23 '05 #1
11 2439
ga*******@voila.fr wrote:
I am facing the following scenario: I have a class 'A', that implements
some concept C -- but we know this, not because A inherits from a
virtual class 'C', but only because a trait tell us so:

class A {};

template <typename T>
struct Is_C
{
static const bool value = false;
};

template <>
struct Is_C<A>
{
static const bool value = true;
};
What I would like to do is, given an instance 'a' of A, call a function
'foo(a)' that would have specific code for class A -- and have default
code for other classes.

The following

template < typename T >
void foo(T t)
{
if (Is_C<T>::value)
{
/* ... */
}
else
{
/* ... */
}
}

would work, but then, it is not extensible to another trait 'Is_D'
unless I modify the function foo. Ideally I would have a function foo
for the general case (corresponding to the 'else') and as many
functions foo for all the different tests, but I am not sure how to do
that. I would like to use the boost::enable_if, but if I use function
overloading, I need to have a disable_if in my 'general case' foo for
each 'specialized' foo:

// General case
template < typename T >
typename disable_if<Is_C<T> >::type // This has to be modified if
another foo is added
foo(T t)
{
/* ... */
}

// Specialization for concept C
template < typename T >
typename enable_if<Is_C<T> >::type
foo(T t)
{
/* ... */
}

I would really appreciate any suggestion for this problem.
Interesting problem. Of course, the first think I want to say is that
you're confusing yourself and others calling your "traits" 'Is_C' or
'Is_D'. Apparently your class A _isn't_ C or D, otherwise inheritance
should work just fine. You should name your concept as it is, something
like 'implements_C' or 'implements_D'.

Anyway... I thought of providing the helper for your 'foo':
------------------------------------------------------------------------
#include <iostream>

template<class T> struct implements_C { enum { value = 0 }; };

template<class T, bool b> struct foo_helper {
static void foo(T t)
{
std::cout << "Generic foo\n";
}
};

template<class T> struct foo_helper<T, true> {
static void foo(T t)
{
std::cout << "'true'-specific foo\n";
}
};

template<class T> void foo(T t)
{
foo_helper<T, implements_C<T>::value>::foo(t);
}

class A {};
class B {};

template<> struct implements_C<A> { enum { value = 1 }; };

int main()
{
A a;
foo(a);
B b;
foo(b);
}
------------------------------------------------------------------------

Now, if you need to add another "policy", the 'foo_helper', which does
the actual work, shouldn't change. What you change is the 'foo':
template<class T> void foo(T t)
{
foo_helper<T,
implements_C<T>::value || implements_D<T>::value::foo(t);

}

Here is amended code with two policies:
------------------------------------------------------------------------
#include <iostream>

template<class T> struct implements_C { enum { value = 0 }; };
template<class T> struct implements_D { enum { value = 0 }; };

template<class T, bool b> struct foo_helper {
static void foo(T t)
{
std::cout << "Generic foo\n";
}
};

template<class T> struct foo_helper<T, true> {
static void foo(T t)
{
std::cout << "'true'-specific foo\n";
}
};

template<class T> void foo(T t)
{
foo_helper<T, implements_C<T>::value || implements_D<T>::value >::foo(t);
}

class A {};
class B {};
class AB {};
class C {};

template<> struct implements_C<A> { enum { value = 1 }; };
template<> struct implements_D<B> { enum { value = 1 }; };
template<> struct implements_C<AB> { enum { value = 1 }; };
template<> struct implements_D<AB> { enum { value = 1 }; };

int main()
{
A a;
foo(a);
B b;
foo(b);
AB ab;
foo(ab);
C c;
foo(c);
}
--------------------------------------------------------------------

HTH

V
Jul 23 '05 #2
Thanks for your answer. However, my problem is slightly different --
let me explain further. I want to leave the possibility open to add a
third function foo in case somebody comes up with another concept D for
which foo should be implemented differently. E.g:

// General case
template < typename T >
// the following line has been modify when third foo was added
typename disable_if<implements_C<T> || implements_D<T> >::type
foo(T t)
{
/* ... */
}

// Specialization for concept C
template < typename T >
typename enable_if<implements_C<T> >::type
foo(T t)
{
/* ... */
}

// Specialization for concept D
template < typename T >
typename enable_if<implements_D<T> >::type
foo(T t)
{
/* ... */
}
One could generalize your idea of helper functions by replacing a bool
by an integer, but I don't like the idea of having to modify the helper
function -- in that sense, I am not sure what benefits come from you
approach compared to the previous collection of functions. Ideally
somebody should be able to add a 'foo' without having to modify the
remaining of the code.

Jul 23 '05 #3
ga*******@voila.fr wrote:
Thanks for your answer. However, my problem is slightly different --
let me explain further. I want to leave the possibility open to add a
third function foo in case somebody comes up with another concept D for
which foo should be implemented differently.

What you need could be achieved by adding a 'tag' inside your traits
class. For example, here's some pseudocode:

struct ATag { };
struct BTag { };
struct CTag { };

template <typename TYPE>
struct Traits;

class SomeClassThatHasATrait { ... };
class SomeClassThatHasBTrait { ... };
class SomeClassThatHasCTrait { ... };

template <>
struct Traits<SomeClassThatHasATrait> { typedef ATag Tag; };

template <>
struct Traits<SomeClassThatHasBTrait> { typedef BTag Tag; };

template <>
struct Traits<SomeClassThatHasCTrait> { typedef CTag Tag; };

template <typename TYPE>
void foo(TYPE object, ATag)
{
... code for types that have A trait ....
}

template <typename TYPE>
void foo(TYPE object, BTag)
{
... code for types that have B trait ....
}

template <typename TYPE>
void foo(TYPE object, CTag)
{
... code for types that have C trait ....
}

template <typename TYPE>
void foo(TYPE object)
{
typedef typename Traits<TYPE>::Tag Tag;
foo(object, Tag());
}

-----------------------------------------

Now, when you want to add a new 'D' trait, all you have to do is define
a tag for it:

struct DTag { };

Define some class that has the D trait:

class SomeClassThatHasDTrait { ... };

template <>
struct Traits<SomeClassThatHasDTrait> { typedef DTag Tag; };

Next, define a foo function for classes that have the D trait:

template <typename TYPE>
void foo(TYPE object, DTag)
{
... code for types that have C trait ....
}
Hope this helps,
-shez-

Jul 23 '05 #4
Shezan Baig wrote:
ga*******@voila.fr wrote:
Thanks for your answer. However, my problem is slightly different --
let me explain further. I want to leave the possibility open to add a
third function foo in case somebody comes up with another concept D for
which foo should be implemented differently.
What you need could be achieved by adding a 'tag' inside your traits
class. For example, here's some pseudocode:

struct ATag { };
struct BTag { };
struct CTag { };

template <typename TYPE>
struct Traits;


This has to be somehow defined for "any other type TYPE".

class SomeClassThatHasATrait { ... };
class SomeClassThatHasBTrait { ... };
class SomeClassThatHasCTrait { ... };
[...]

template <typename TYPE>
void foo(TYPE object)
{
typedef typename Traits<TYPE>::Tag Tag;
And it's not going to compile if there is no 'Tag' defined. You'll
need to have some kind of "default traits" and the corresponding
"default" behaviour.
foo(object, Tag());
}


V
Jul 23 '05 #5


Victor Bazarov wrote:
Shezan Baig wrote:
ga*******@voila.fr wrote:
Thanks for your answer. However, my problem is slightly different --
let me explain further. I want to leave the possibility open to add a
third function foo in case somebody comes up with another concept D for
which foo should be implemented differently.


What you need could be achieved by adding a 'tag' inside your traits
class. For example, here's some pseudocode:

struct ATag { };
struct BTag { };
struct CTag { };

template <typename TYPE>
struct Traits;


This has to be somehow defined for "any other type TYPE".

class SomeClassThatHasATrait { ... };
class SomeClassThatHasBTrait { ... };
class SomeClassThatHasCTrait { ... };
[...]

template <typename TYPE>
void foo(TYPE object)
{
typedef typename Traits<TYPE>::Tag Tag;


And it's not going to compile if there is no 'Tag' defined. You'll
need to have some kind of "default traits" and the corresponding
"default" behaviour.


Yeap. If you need default behaviour, then instead of:

template <typename TYPE>
struct Traits;

you need to do:

template <typename TYPE>
struct Traits {
typedef DefaultTag Tag;
};

and create a corresponding foo(TYPE, DefaultTag) function.

-shez-

Jul 23 '05 #6
This is indeed in the spirit of what I was looking for. It is still one
footstep of being exactly what I need though, because it doesn't reuse
the information that was already there in the implements_X classes. In
the first place I thought that this problem is hard precisely because
the information is not encoded in the form of class types -- and your
solution is exactly going manually from one form to the other. Is there
a way to go without having to rewrite all these traits specialization?

B.

Jul 23 '05 #7
ga*******@voila.fr wrote:
This is indeed in the spirit of what I was looking for. It is still one
footstep of being exactly what I need though, because it doesn't reuse
the information that was already there in the implements_X classes. In
the first place I thought that this problem is hard precisely because
the information is not encoded in the form of class types -- and your
solution is exactly going manually from one form to the other. Is there
a way to go without having to rewrite all these traits specialization?

B.

Specialize the trait. Its hardly much typing! And even less if you
just copy&paste :)

-shez-

Jul 23 '05 #8
That's not that simple. Suppose 'foo' now depends on three parameters,
and I want to specialized foo when all three parameters have a true
std::numeric_limits<>::is_specialized. There is no copy-pasting
possible. And can you just imagine the number of specialized traits I
would have to type?

Jul 23 '05 #9
gao_bo...@voila.fr wrote:
That's not that simple. Suppose 'foo' now depends on three parameters,
and I want to specialized foo when all three parameters have a true
std::numeric_limits<>::is_specialized. There is no copy-pasting
possible. And can you just imagine the number of specialized traits I
would have to type?

All you need is one tag per overloaded 'foo'. And one specialization
per 'TYPE' that 'foo' can operate on.

Jul 23 '05 #10
I am not sure what you mean. For the example I was mentioning, the
enable_if solution would be

// general case
template <typename T1, typename T2, typename T3 >
typename disable_if_c<
numeric_traits<T1>::is_specialized &&
numeric_traits<T2>::is_specialized &&
numeric_traits<T3>::is_specialized
::type foo(const T1 &x1, const T2 &x2, const T3 &x3)
{
/*...*/
}

// case when all types have numeric traits
template <typename T1, typename T2, typename T3 >
typename enable_if_c<
numeric_traits<T1>::is_specialized &&
numeric_traits<T2>::is_specialized &&
numeric_traits<T3>::is_specialized::type

foo(const T1 &x1, const T2 &x2, const T3 &x3)
{
/*...*/
}

What would be the equivalent with your technique? I can see that I
would need only one tag, for the case when all types have numeric
traits, but how would I avoid having a trait with three template
arguments, and having to specialize this trait for all 3-uples of types
with known numeric traits (and there are a lot of them) ? How could I
reuse numeric traits?

Bolin

Jul 23 '05 #11
ga*******@voila.fr wrote:
I am not sure what you mean. For the example I was mentioning, the
enable_if solution would be

// general case
template <typename T1, typename T2, typename T3 >
typename disable_if_c<
numeric_traits<T1>::is_specialized &&
numeric_traits<T2>::is_specialized &&
numeric_traits<T3>::is_specialized
::type

foo(const T1 &x1, const T2 &x2, const T3 &x3)
{
/*...*/
}

// case when all types have numeric traits
template <typename T1, typename T2, typename T3 >
typename enable_if_c<
numeric_traits<T1>::is_specialized &&
numeric_traits<T2>::is_specialized &&
numeric_traits<T3>::is_specialized
::type

foo(const T1 &x1, const T2 &x2, const T3 &x3)
{
/*...*/
}

What would be the equivalent with your technique? I can see that I
would need only one tag, for the case when all types have numeric
traits, but how would I avoid having a trait with three template
arguments, and having to specialize this trait for all 3-uples of types
with known numeric traits (and there are a lot of them) ? How could I
reuse numeric traits?

Bolin


Create a function like this:
template <typename T1, typename T2, typename T3>
void foo(const T1& x1, IsSpecializedTag,
const T2& x2, IsSpecializedTag,
const T3& x3, IsSpecializedTag)
{
/* ... */
}

template <typename T1, typename T2, typename T3>
void foo(const T1& x1, const T2& x2, const T3& x3)
{
typedef typename Trait<T1>::Tag Tag1;
typedef typename Trait<T2>::Tag Tag2;
typedef typename Trait<T3>::Tag Tag3;

return foo(x1, Tag1(),
x2, Tag2(),
x3, Tag3());
}
Of course, you also have the flexibility to mix and match tags like
this:
template <typename T1, typename T2, typename T3>
void foo(const T1& x1, IsSpecializedTag,
const T2& x2, IsSomethingElseTag,
const T3& x3, IsYetSomethingElseTag)
{
/* ... */
}
and 'foo' will "just work" as long as you have assigned an appropriate
tag for each of the possible types (via specialization).

Hope this helps,
-shez-

Jul 23 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Paul MG | last post by:
Hi Template partial specialization always seems like a fairly straightforward concept - until I try to do it :). I am trying to implement the input sequence type (from Stroustrup section...
2
by: Jeff | last post by:
/* -------------------------------------------------------------------------- Hello, I was experimenting with class templates and specializing member functions and came across a simple problem...
8
by: Massimiliano Alberti | last post by:
Can I specialize a template function in a subclass without overriding it? (the main template function is defined in a base class). Now I'm doing something like that: (in base class)...
5
by: Levent | last post by:
Hi, Why doesn't this work? (tried with gcc 3.3.3 and VC++ 7.1): #include <iostream> template<class T, unsigned N> struct Foo { void func(); }; template<class T, unsigned N>
2
by: Michael Stembera | last post by:
Here is a very simple piece of code to repro this bug. template<typename T, int N> inline bool foo( void ) { return true; } template<typename T> inline bool foo<T, 1>( void ) { return...
6
by: flopbucket | last post by:
Could someone explain to me what the difference is between function template specialization and function overloading? I guess overloading can change the number of parameters, but otherwise they...
4
by: stinos | last post by:
Hi All! suppose a class having a function for outputting data somehow, class X { template< class tType > void Output( const tType& arg ) { //default ToString handles integers/doubles
8
by: mattias.nissler | last post by:
Hi! Here is a problem I ran into at work. The following example doesn't compile on gcc-4.1: struct cons_end {}; template<typename U,typename Vstruct cons { U elem; V tail;
13
by: mike b | last post by:
Hello everyone, thanks in advance for your help. I'm new to C++ templates and have run into some issues using member function templates. I have a shared library containing templates that I'm...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.