Существует значительная разница в значении двух подходов.
Подход 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);