Template specialization for a group of types

Discussion in 'C++' started by Marc Schellens, Nov 20, 2003.

  1. 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
     
    Marc Schellens, Nov 20, 2003
    #1
    1. Advertising

  2. 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;
    }
     
    Patrick Kowalzick, Nov 20, 2003
    #2
    1. Advertising

  3. Marc Schellens

    tom_usenet Guest

    On Thu, 20 Nov 2003 14:25:22 +0900, Marc Schellens
    <> 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
     
    tom_usenet, Nov 20, 2003
    #3
  4. Marc Schellens wrote in news::

    > 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/
     
    Rob Williscroft, Nov 20, 2003
    #4
  5. Marc Schellens

    Chris Theis Guest

    "Patrick Kowalzick" <> wrote in message
    news:bphujb$ri3$...
    > 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
     
    Chris Theis, Nov 24, 2003
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David B. Held
    Replies:
    2
    Views:
    470
    Rob Williscroft
    Oct 26, 2003
  2. Joseph Turian
    Replies:
    2
    Views:
    467
  3. David O
    Replies:
    2
    Views:
    425
    David O
    Jan 10, 2007
  4. Tom
    Replies:
    0
    Views:
    319
  5. mschellens
    Replies:
    9
    Views:
    244
    88888 Dihedral
    Mar 27, 2013
Loading...

Share This Page