I have several functions that I want to specialize based on type qualities, such as "character, signed-integer, unsigned-integer, floating-point, pointer"; using type_traits seems like the way to do this, and have code similar to the to the following:
#include <tr1/type_traits>
#include <iostream>
template<bool, typename _Tp = void>
struct enable_if
{ };
template<typename _Tp>
struct enable_if<true, _Tp>
{
typedef _Tp type;
};
template< typename T >
inline void
foo_impl( typename enable_if< std::tr1::is_integral< T >::value, T >::type const& )
{
std::cout << "This is the function-overloaded integral implementation.\n";
}
template< typename T >
inline void
foo_impl( typename enable_if< std::tr1::is_floating_point< T >::value, T >::type const& )
{
std::cout << "This is the function-overloaded floating-point implementation.\n";
}
template< typename T >
inline void
function_overloads_foo( T const& arg )
{
foo_impl< T >( arg ); // vital to specify the template-type
}
void function_overloads_example()
{
function_overloads_foo( int() );
function_overloads_foo( float() );
}
except in my real code, I also have bar
,baz
, etc., along with foo
.
However, I would like to group all of these functions per quality into one templated class as static
methods. How is this best done? Here's my naive, and broken attempt to use Tags, SFINAE, and partial-specialization:
struct IntegralTypeTag;
struct FloatingPointTypeTag;
template< typename T, typename U = void >
class Foo
{
};
template< typename T >
class Foo< T, typename enable_if< std::tr1::is_integral< T >::value, IntegralTypeTag >::type >
{
static void foo( T const& )
{
std::cout << "This is the integral partial-specialization class implementation.\n";
}
};
template< typename T >
class Foo< T, typename enable_if< std::tr1::is_floating_point< T >::value, FloatingPointTypeTag >::type >
{
static void foo( T const& )
{
std::cout << "This is the floating-point partial-specialization class implementation.\n";
}
};
template< typename T >
inline void
partial_specialization_class_foo( T const& arg )
{
Foo< T >::foo( arg );
}
void partial_specialization_class_example()
{
partial_specialization_class_foo( int() );
partial_specialization_class_foo( float() );
}
Note: in my real code, I'd have bar
,baz
, etc., along with foo
static-methods.
FYI, this is C++03.
As an aside, am I doing the templated function overloading in the conventional way?
IntegralTypeTag
in theenable_if
will get in the way. The default for the second parameter ofFoo
isvoid
, which is not the same asIntegralTypeTag
, so the specialization ofFoo
will fail to match.Ie,
Foo< int, void >
(which is what you get when you doFoo<int>
) does not matchFoo< int, IntegralTypeTag >
, which your intendedint
specialization is (after theenable_if
logic).Tagging is the result of a
type_traits
class, which you can then use to simplify othertype_traits
classes.Here is one approach:
After observing Vaughn's correct answer, I wanted to simplify it more. I was able to remove the use of Tags and extra trait-classes to come up with the following structure:
I think this works by providing two template-type parameters to the class, where the second one is compile-time conditional:
enable_if
fails, the whole partial-specialization is unavailable to match against.I find it less cumbersome to understand, comparatively.