Template specialization for a list of types

Discussion in 'C++' started by mschellens, Mar 20, 2013.

  1. mschellens

    mschellens Guest

    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
     
    mschellens, Mar 20, 2013
    #1
    1. Advertising

  2. mschellens

    Luca Risolia Guest

    On 20/03/2013 23:36, mschellens wrote:
    > 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>());
    }
     
    Luca Risolia, Mar 20, 2013
    #2
    1. Advertising

  3. mschellens

    mschellens Guest

    On Thursday, March 21, 2013 12:48:20 AM UTC+1, Luca Risolia wrote:
    > On 20/03/2013 23:36, mschellens wrote:
    >
    > > 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>());
    >
    > }


    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
     
    mschellens, Mar 21, 2013
    #3
  4. mschellens

    Luca Risolia Guest

    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<
    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<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<
    bool,
    !(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(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..
     
    Luca Risolia, Mar 21, 2013
    #4
  5. Luca Risoliaæ–¼ 2013å¹´3月22日星期五UTC+8上åˆ2時47分29秒寫é“:
    > 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<
    >
    > 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<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<
    >
    > bool,
    >
    > !(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(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++.
     
    88888 Dihedral, Mar 22, 2013
    #5
  6. mschellens

    mschellens Guest

    On Thursday, March 21, 2013 7:47:29 PM UTC+1, Luca Risolia wrote:
    > 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<
    >
    > 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<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<
    >
    > bool,
    >
    > !(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(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() {}
    };
     
    mschellens, Mar 25, 2013
    #6
  7. mschellensæ–¼ 2013å¹´3月25日星期一UTC+8下åˆ5時57分56秒寫é“:
    > On Thursday, March 21, 2013 7:47:29 PM UTC+1, Luca Risolia wrote:
    >
    > > 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<

    >
    > >

    >
    > > 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<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<

    >
    > >

    >
    > > bool,

    >
    > >

    >
    > > !(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(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 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.
     
    88888 Dihedral, Mar 25, 2013
    #7
  8. mschellens

    Stefan Ram Guest

    A Google Groups user writes:
    >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).
     
    Stefan Ram, Mar 25, 2013
    #8
  9. mschellens

    mschellens Guest

    On Monday, March 25, 2013 9:22:50 PM UTC+1, 88888 Dihedral wrote:
    > mschellensæ–¼ 2013å¹´3月25日星期一UTC+8下åˆ5時57分56秒寫é“:
    >
    > > On Thursday, March 21, 2013 7:47:29 PM UTC+1, Luca Risolia wrote:

    >
    > >

    >
    > > > 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<

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > 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<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<

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > bool,

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > !(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(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() {}

    >
    > >

    >
    > > };

    >
    > 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."
     
    mschellens, Mar 27, 2013
    #9

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

    Don't you do abbreviations for some nouns of words?
     
    88888 Dihedral, Mar 27, 2013
    #10
    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:
    480
    Rob Williscroft
    Oct 26, 2003
  2. Marc Schellens
    Replies:
    4
    Views:
    646
    Chris Theis
    Nov 24, 2003
  3. Joseph Turian
    Replies:
    2
    Views:
    485
  4. David O
    Replies:
    2
    Views:
    444
    David O
    Jan 10, 2007
  5. Tom
    Replies:
    0
    Views:
    329
Loading...

Share This Page