Transforming a parameterization by two classes to a parameterization by one class

后端 未结 3 2035
感情败类
感情败类 2021-01-22 14:33

The following code has a little bit of unpleasantness.

#include 

template struct PA1 {}; template struct QA1          


        
相关标签:
3条回答
  • 2021-01-22 15:06

    As I understand the question and its predecessors, the task is a specialization of function template on a class template regardless of its template parameter.

    Generic solution:

    #include <cassert>
    //remember the value of the argument S to retrieve it later
    template<typename S> struct PA1 { typedef S S; };
    template<typename S> struct PA2 { typedef S S; };
    template<typename S> struct PB  { typedef S S; };
    template<typename S> struct PC  { typedef S S; };
    
    //helper: generic version of fn for any parameters except PB и PC
    template<typename T, typename S>
    struct FN
    {
        static char fn() { return 'a'; }
    };
    //helper: fn specialized for class template PB
    template<typename S>
    struct FN<PB<S>, S>
    {
        static char fn() { return 'b'; }
    };
    //helper: fn specialized for class template PC
    template<typename S>
    struct FN<PC<S>, S>
    {
        static char fn() { return 'c'; }
    };
    
    //fn relies on compiler's type deduction to avoid specifying of template parameter explicitly
    template<typename T>
    char fn(T t)
    {
        return FN< T, T::S>::fn();
    }
    //usage
    int main()
    {
        PA1<int> pa1;
        PA2<char> pa2;
        PB<float>  pb;
        PC<double>  pc;
        assert( (fn(pa1)) == 'a' );
        assert( (fn(pa2)) == 'a' );
        assert( (fn(pb)) == 'b' );
        assert( (fn(pc)) == 'c' );
    }
    

    Applying this method to your case:

    #include <cassert>
    
    template<typename S> struct PA1 { typedef S S; }; template<typename S> struct QA1 {};
    template<typename S> struct PA2 { typedef S S; }; template<typename S> struct QA2 {};
    template<typename S> struct PB  { typedef S S; }; template<typename S> struct QB  {};
    template<typename S> struct PC  { typedef S S; }; template<typename S> struct QC  {};
    
    template<typename S> struct A1 { typedef PA1<S> P; typedef QA1<S> Q; };
    template<typename S> struct A2 { typedef PA2<S> P; typedef QA2<S> Q; };
    template<typename S> struct B  { typedef PB<S>  P; typedef QB<S>  Q; };
    template<typename S> struct C  { typedef PC<S>  P; typedef QC<S>  Q; };
    
    template<typename T, typename S>
    struct FN
    {
        static char fn() { return 'a'; }
    };
    template<typename S>
    struct FN<PB<S>, S>
    {
        static char fn() { return 'b'; }
    };
    template<typename S>
    struct FN<PC<S>, S>
    {
        static char fn() { return 'c'; }
    };
    
    template<typename A>
    char fn() //or char fn(A* a)
    {
        return FN<A::P, A::P::S>::fn();
    }
    
    template<typename T>
    struct Action
    {
        char z;
        //so the constructor accepts only correct combinations of p and q 
        Action(typename T::P p, typename T::Q q)
        {
            z = fn<T>(); //or fn((T*)NULL);
        }
    };    
    int main()
    {
        PA1<int> pa1; QA1<int> qa1;
        PA2<int> pa2; QA2<int> qa2;
        PB<int>  pb;  QB<int>  qb;
        PC<int>  pc;  QC<int>  qc;
    
        Action<A1<int> > aa1 = Action<A1<int> >(pa1, qa1);    assert( aa1.z == 'a' );
        Action<A2<int> > aa2 = Action<A2<int> >(pa2, qa2);    assert( aa2.z == 'a' );
    
        Action<B<int> > ab = Action<B<int> >(pb, qb );    assert( ab.z == 'b' );
        Action<C<int> > ac = Action<C<int> >(pc, qc );    assert( ac.z == 'c' );
    }
    
    0 讨论(0)
  • 2021-01-22 15:07

    C++0x will have template aliases

    Oh and to track when it comes to GNU C++: http://gcc.gnu.org/projects/cxx0x.html

    0 讨论(0)
  • 2021-01-22 15:28

    If you want type A to be automatically inferred, then no such modification is possible unless you have fn take an argument of type A (or A& or A* etc) and consequently force the user to pass in a value of that type.

    On the other hand, if you don't mind forcing the caller to specify the template argument explicitly, then that syntax is already fine.

    There's no happy medium.

    0 讨论(0)
提交回复
热议问题