通过两个类将参数化转换为一个类的参数化

时间:2011-04-13 08:53:12

标签: c++

以下代码有点不愉快。

#include <cassert>

template<typename S> struct PA1 {}; template<typename S> struct QA1 {};
template<typename S> struct PA2 {}; template<typename S> struct QA2 {};
template<typename S> struct PB  {}; template<typename S> struct QB  {};
template<typename S> struct PC  {}; 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 PA, typename QA>
char fn(PA, QA) {
    return 'a';
}

template<typename S> char fn(PB<S>, QB<S>) { return 'b'; }
template<typename S> char fn(PC<S>, QC<S>) { return 'c'; }

template<typename T>
struct Action
{
    char z;
    Action(typename T::P p, typename T::Q q)
    {
        z = fn(p, q);
    }
};

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;

    assert( fn(pa1, qa1) == 'a' );
    assert( fn(pa2, qa2) == 'a' );

    assert( fn(pb, qb) == 'b' );
    assert( fn(pc, qc) == 'c' );

    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' );
}

即使PA和QA总是串联出现(带有QA1的PA1和带有QA2的PA2),我们写

template<typename PA, typename QA>
char fn(PA, QA) { ... }

会好得多
template<typename A>
char fn(typename A::P, typename A::Q) {
    return 'a';
}

你能否建议进行修改以使其成为可能?

3 个答案:

答案 0 :(得分:0)

如果您希望自动推断类型A,那么除非您fn采用A类型的参数(或A&或{{}},否则无法进行此类修改{1}}等)并因此强制用户传入该类型的值。

另一方面,如果您不介意强制调用者明确指定模板参数,那么该语法已经很好了。

没有幸福的媒介。

答案 1 :(得分:0)

C ++ 0x将有template aliases

哦,跟踪GNU C ++的时间:http://gcc.gnu.org/projects/cxx0x.html

答案 2 :(得分:0)

根据我对该问题及其前身的理解,该任务是类模板上函数模板的特化,无论其模板参数如何。

通用解决方案:

#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' );
}

将此方法应用于您的案例:

#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' );
}