本文介绍了将两类的参数化转换为一类的参数化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
以下代码有一些不愉快之处.
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' );
}
这篇关于将两类的参数化转换为一类的参数化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!