Search code examples
c++templatesstatic-methodssfinaepartial-specialization

How To Convert Templated Function Overloads to Partial-Specialized Templated Class Static Methods?


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?


Solution

  • Here is one approach:

    #include <tr1/type_traits>
    #include <iostream>
    
    struct IntegralTypeTag;
    struct FloatingPointTypeTag;
    
    template <
      typename T,
      bool is_integral = std::tr1::is_integral<T>::value,
      bool is_floating_point = std::tr1::is_floating_point<T>::value
    > struct TypeTag;
    
    template <typename T>
    struct TypeTag<T,true,false> {
      typedef IntegralTypeTag Type;
    };
    
    template <typename T>
    struct TypeTag<T,false,true> {
      typedef FloatingPointTypeTag Type;
    };
    
    template <typename T,typename TypeTag = typename TypeTag<T>::Type> struct Foo;
    
    
    template <typename T>
    struct Foo<T,IntegralTypeTag> {
      static void foo( T const& )
      {
        std::cout << "This is the integral partial-specialization class implementation.\n";
      }
    };
    
    template <typename T>
    struct Foo<T,FloatingPointTypeTag> {
      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 );
    }
    
    int main(int,char**)
    {
      partial_specialization_class_foo(int());
      partial_specialization_class_foo(float());
      return 0;
    }