С ++ черты характера в дизайне - PullRequest
0 голосов
/ 06 июля 2018

рассмотреть определение

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;

Мой вопрос: есть ли существенная разница между этими двумя образцами, кроме современности черт? Есть ли что-то, что можно сделать с одним, но не с другим? Может быть, лучше вопросы, когда вы называете что-то черта?

1 Ответ

0 голосов
/ 06 июля 2018

Существует значительная разница в значении двух подходов.

Подход 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);
...