C : Возможно ли использовать динамическую привязку с параметром шаблона?

#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 подход — исключительно потому, что это более просто для понимания! 🙂