将两类的参数化转换为一类的参数化 [英] Transforming a parameterization by two classes to a parameterization by one class

查看:56
本文介绍了将两类的参数化转换为一类的参数化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码有一些不愉快之处.

The following code has a little bit of unpleasantness.

#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总是串联出现(PA1与QA1以及PA2与QA2),我们还是写

Even though PA and QA always arise in tandem (PA1 with QA1 and PA2 with QA2), we write

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

写起来会更好

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

您能建议进行修改以使之成为可能吗?

Can you suggest a modification that would make that possible?

推荐答案

据我了解的问题及其前身,任务是在类模板上对功能模板进行专业化处理,而不论其模板参数如何.

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.

通用解决方案:

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

这篇关于将两类的参数化转换为一类的参数化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆