考虑定义
class A1{/*something*/};
以下两个选项
1)使用助手
struct A1_helper{ typedef A1 underlying; //let A1_helper user direct access to A1 //whatever else necessary to work with A1... }; template<typename A_helper> class B { //use A_helper }; B<A1_helper> b;
2)使用特征
template<A> struct A_traits{ //whatever necessary to work with A... }; template<typename A> class B2 { //use A_traits<A> }; B<A> b;
我的问题是:除了特征的现代性,这两种设计之间是否存在本质区别?有什么可以用一个做的但不能用另一个做的吗?也许是一个更好的问题,什么时候您称其为特质?
答案 0 :(得分:1)
这两种方法的含义存在显着差异。
方法1允许用户自定义每个站点如何执行A型处理。
struct A_helper_1 {
static int to_int(A a) { return 1; }
};
struct A_helper_2 {
static int to_int(A a) { return 2; }
};
A a;
B<A_helper_1> b1;
b1.printA(a);
B<A_helper_2> b2;
b2.printA(a);
使用方法2时,A类只有一个真实的行为。
template<>
struct Helper<A> {
static int to_int(A a) { return 1; }
};
A a;
B<A> b;
b.printA(a);
方法2-如果您想要一种新的行为,则需要包装您的课程
struct A2 : public A {/* ... all the constructors etc. ... */ }
template<>
struct Helper<A2> {
static int to_int(A2 a) { return 1; }
}
B<A> b1;
B<A2> b2;
A a;
b1.printA(a);
// Only OK if you have a conversion operator in A2 - but will create a temp copy!
b2.printA(a);
A2 a2;
b1.printA(a2); // OK but might copy a slice depending on call signature
b2.printA(a2);
因此,IMO使用方法1暗示底层代码是可扩展的,而方法2则不是,因为1的扩展容易得多,但其实例化却更加冗长(B<A_helper>
与B<A>
)。
值得注意的是,使用方法1可以解决一些冗长的问题,方法是执行以下附加步骤,并使用C
代替B
。
template<typename T>
struct default_helper;
template<typename T>
using C = B<default_helper<T>>
template<>
struct default_helper<A> {
static int to_int(A a) { return 1; }
}
A a;
C<A> c;
c.printA(a);