#c #templates #inheritance
#c #шаблоны #наследование
Вопрос:
У меня есть шаблонная функция, которая принимает объект-функцию (‘functor’) в качестве параметра шаблона:
template <typename Func> int f (void) {
Func func;
return func ();
};
struct Functor {
virtual int operator () (void) = 0;
};
struct Functor0 : Functor {
int operator () (void) {
return 0;
}
};
struct Functor1 : Functor {
int operator () (void) {
return 1;
}
};
Я хочу избежать if-else
блока, подобного:
int a;
if (someCondition) {
a = f<Functor0> ();
}
else {
a = f<Functor1> ();
}
Есть ли способ использовать что-то похожее на динамическую привязку, то есть что-то вроде:
a = f<Functor> (); // I know this line won't compile, it is just an example of what I need
и решить во время выполнения, какой (производный) тип передается в качестве параметра шаблона?
Комментарии:
1. Я не понимаю, зачем здесь нужны шаблоны — разве это не простой пример полиморфизма во время выполнения?
2. Вы могли бы избежать
if
/else
сa = someCondition ? f<Functor0>() : f<Functor1>();
3. @unapersson — Это хороший вопрос — Я пытаюсь очистить некоторый существующий код, и мой вопрос просто возник у меня в голове при этом — я уверен, что его можно решить, используя только полиморфизм, но я все равно хотел знать ответ. @Chris Lutz — это просто другой синтаксис для
if/else
, нет?
Ответ №1:
Есть ли способ использовать что-то похожее на динамическую привязку
Нет. Это принципиально невозможно. В какой-то момент в вашем коде вам нужно иметь различие регистра. Конечно, это не обязательно писать вручную; вы можете использовать макросы (или снова шаблоны) для генерации необходимого кода. Но это должно быть там.
Ответ №2:
Один из способов избежать проверки (если это ДЕЙСТВИТЕЛЬНО то, что вы хотите сделать), это использовать массив — ..
Functor* fp[] = { new Functor0(), new Functor1() };
теперь — используйте someCondition
в качестве индекса.
a = (*fp[someCondition])();
это зависит просто от полиморфизма во время выполнения, а не от используемого вами механизма избыточных шаблонов… (кстати. не забудьте очистить!)
Конечно, это неприятно и откровенно избыточно, накладные расходы if
будут незначительными, но ясность, которую это добавляет к коду, значительна…
Комментарии:
1.очистки можно было бы избежать, используя,
Functor constamp; fp[]
если бы операция выполняласьoperator()
const
, или используя некоторые интеллектуальные указатели (boost::scoped_ptr
/std::unique_ptr
) в противном случае.2. @Matthieu M, конечно, я просто хотел выделить подход и указать, что, скорее всего, лучше использовать
if
подход — исключительно потому, что это более просто для понимания! 🙂