В принципе, если тестовая переменная msg.qty
не является постоянной времени компиляции, это будет невозможно. Вы должны понимать, что шаблоны могут использоваться для достижения статического полиморфизма, тогда как ООП (наследование) может использоваться для достижения динамического полиморфизма. Другими словами, шаблоны разрешаются во время компиляции, тогда как вызовы виртуальных функций разрешаются во время выполнения. Вы можете использовать оба одновременно, но вы не можете использовать их с той же целью (т. Е. Они являются парадигмами дополнительного программирования, каждый из которых имеет свои собственные контексты приложения).
Если бы вы могли, однако, получить msg.qty
быть константой во время компиляции типа Msg
(т.е. Msg::qty
, как enum
или static const
), то вы можете использовать boost::enable_if
библиотеку. Как так:
template <class Msg>
typename boost::enable_if<Msg::qty < 100, EncodedMsg<short> >::type*
encode(const Msg& msg) { return new EncodedMsd<short>(...); };
template <class Msg>
typename boost::enable_if<((Msg::qty >= 100) && (Msg::qty < 100000)), EncodedMsg<short> >::type*
encode(const Msg& msg) { return new EncodedMsd<int>(...); };
template <class Msg>
typename boost::enable_if<Msg::qty >= 100000, EncodedMsg<short> >::type*
encode(const Msg& msg) { return new EncodedMsd<long>(...); };
Но в том случае, если вы можете определить, для определенного класса Msg, какой шаблон конкретизации использовать для EncodedMsg, то это намного проще определить его в качестве вложенного ЬурейеГо в классе Msg, и определить свою функцию кодирования следующим образом:
template <class Msg>
Msg::encoded_type* encode(const Msg& msg) { return new Msg::encoded_type(...); };
вы также можете использовать тип признак (например, message_trait или что-то в этом роде), чтобы определить вложенные ЬурейиЙ, если у вас есть классы сообщений, которые не могут быть изменены.
Но, если msg.qty может быть только значением времени выполнения, тогда нет выбора, кроме как использовать динамический полиморфизм (т. Е. Вернуть указатель на базовый класс или интерфейс).Или вы также можете использовать boost::variant
. В этом случае, вы можете сделать это:
boost::variant< EncodedMsg<short>,
EncodedMsg<int>,
EncodedMsg<long> >* encode(const Msg& msg)
{
typedef boost::variant< EncodedMsg<short>,
EncodedMsg<int>,
EncodedMsg<long> > result_type;
if(msg.qty < 100)
return new result_type(EncodedMsg<short>(...));
else if(msg.qty < 100000)
return new result_type(EncodedMsg<int>(...));
else
return new result_type(EncodedMsg<long>(...));
};
выше имеет некоторые очевидные проблемы (например, тот факт, что тип результата будет столь же большим, как самый большой из шаблона инстанциаций EncodedMsg, но вы могли бы решить, что с дополнительный уровень косвенности (сохранение указателей на объекты EncodedMsg)). И это не так хорошо и эффективно, как полиморфная альтернатива, если вы можете ее найти.