Безопасен ли этот способ перегрузки функций для иерархий классов с использованием шаблонов?

Хорошо, это немного сложно, поэтому, пожалуйста, потерпите меня.:)

У нас есть эта простая иерархия классов:

class A {};
class DA : public A {};
class DDA : public DA {};

И у нас есть следующие функции, работающие с этими классами:

void f(A x) {
  std::cout << "f A" << std::endl;
}
void f(DA x) {
  std::cout << "f DA" << std::endl;
}
void f(DDA x) {
  std::cout << "f DDA" << std::endl;
}

Теперь мы хотим добавить еще одну функцию, которая немного по-другому обрабатывает DA.

(1 )Первая попытка может выглядеть так:

void g(A t) {
  std::cout << "generic treatment of A" << std::endl;
  std::cout << "called from g: ";
  f(t);
}
void g(DA t) {
  std::cout << "special treatment of DA" << std::endl;
  std::cout << "called from g: ";
  f(t);
}

Но вызов этого с объектом каждого из классов явно не дает желаемого эффекта.

Звоните:

  A a; DA b; DDA c;
  g(a); g(b); g(c)

Результат:

generic treatment of A
called from g: f A
special treatment of DA
called from g: f DA
special treatment of DA
called from g: f DA        //PROBLEM: g forgot that this DA was actually a DDA

(2 )Вместо этого мы можем попробовать использовать шаблоны:

template
void h(T t) {
  std::cout << "generic treatment of A" << std::endl;
  std::cout << "called from h: ";
  f(t);
}

template<>
void h<>(DA t) {
  std::cout << "special treatment of DA" << std::endl;
  std::cout << "called from h: ";
  f(t);
}

что приводит к:

generic treatment of A
called from h: f A
special treatment of DA
called from h: f DA
generic treatment of A    //PROBLEM: template specialization is not used
called from h: f DDA

Хорошо, а как насчет того, чтобы не использовать специализацию шаблона, а определить функцию шаблона, отличную от -, для особого случая?(Статья по очень запутанному делу. )Оказывается, он ведет себя точно так же, потому что не--шаблонная функция, которая, согласно статье, является "гражданином первого сорта", похоже, проигрывает, потому что для ее использования необходимо преобразование типа. А если бы его использовали, то мы просто вернулись бы к первому решению (я полагаю )и забыли бы о типе DDA.

( 3 )Теперь я наткнулся на этот код на работе, который кажется мне довольно причудливым:

template
void i(T t, void* magic) {
  std::cout << "generic treatment of A" << std::endl;
  std::cout << "called from i: ";
  f(t);
}

template
void i(T t, DA* magic) {
  std::cout << "special treatment of DA" << std::endl;
  std::cout << "called from i: ";
  f(t);
}

Но, похоже, он делает именно то, что я хочу:

generic treatment of A
called from i: f A
special treatment of DA
called from i: f DA
special treatment of DA
called from i: f DDA

Несмотря на то, что он должен называться как-то странно :я (а, &а ); я (б, &б ); я (с, и с );

Теперь у меня есть несколько вопросов:

  1. Почему, черт возьми, это работает?
  2. Как вы думаете, это хорошая идея? Где возможны подводные камни?
  3. Какие еще способы такой специализации вы бы предложили?
  4. (Как преобразования типов вписываются в безумие частичного упорядочения шаблонов и тому подобное...)

Надеюсь, это было достаточно ясно.:)

5
задан Sarien 25 July 2012 в 13:37
поделиться