我有可以创建许多不同模板类型的函数;问题的一个简单例子是:
EncodedMsg<?>* encode(const Msg& msg)
{
if(msg.qty < 100)
return new EncodedMsg<short>(...);
else if(msg.qty < 100000)
return new EncodedMsg<int>(...);
else
return new EncodedMsg<long>(...);
}
我遇到的问题是:
有人能想到解决这个问题的方法吗?
答案 0 :(得分:8)
您正试图以动态方式使用模板,这是不可能的。模板的类型必须在编译时知道,因此您无法根据一系列条件进行区分。
要在运行时更改类型,您需要来自类和继承的多态性。
答案 1 :(得分:3)
基本上,如果测试变量msg.qty
不是编译时常量,那么这是不可能的。您必须了解模板可用于实现静态多态,而OOP(继承)可用于实现动态多态。换句话说,模板在编译时解析,而虚拟函数调用在运行时解析。您可以同时使用它们,但不能将它们用于相同的目的(即它们是互补的编程范例,每个范例都有自己的应用程序上下文)。
但是,如果可以,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中将它定义为嵌套的typedef要容易得多,并定义你的编码函数如下:
template <class Msg>
Msg::encoded_type* encode(const Msg& msg) { return new Msg::encoded_type(...); };
如果您有不可修改的消息类,您还可以使用类型特征(如message_trait或类似的东西)来定义嵌套的typedef。
但是,如果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对象的指针)解决这个问题) 。如果你能找到它,它就不如多态替代方案那么好用和高效。
答案 2 :(得分:1)
1)您不能重载函数的返回类型,但可以重载类型 传递给函数并通过指针传递。但是,我认为这不是你想要的,见2)
2)基本上必须使用不同的设计方法来解决问题: 通过在基类中使用虚拟接口,您的方法将返回正确的接口 class,只有一个调用正确的虚函数。您只需返回基类(EncodedMsgBase),它可以是EncodedMsg_whatever,只要它是从EncodedMsgBase派生的。如果需要,可以从基类创建模板。
在更复杂的场景中,这归结为“如何在c ++中创建工厂”问题。人们通常通过传递实现'虚拟构造函数idiom'的基类来解决这个问题。
检查c ++ faq以获取更多信息:
http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.8
另请注意,通过使用静态类型可以避免很多麻烦:)
答案 3 :(得分:0)
此方法不允许您在希望进一步的任何地方使用EncodedMessage
(因为我怀疑,例如,EncodedMessage<long>
和EncodedMessage<short>
都应该可以通过一些方法,对EncodedMessages
)进行操作。
虽然您要求的技巧可以通过技巧完成,但我建议您重新考虑您的架构。
如果可以将EncodedMessage<long>
用于所有邮件数量,您可以直接使用TheOnlyPossibleEncodedMessage
并将其定义为{{1}}。