以下代码有点不愉快。
#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';
}
你能否建议进行修改以使其成为可能?
答案 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' );
}