如何避免在C ++中无法重载返回类型

时间:2011-02-07 18:52:36

标签: c++

我有可以创建许多不同模板类型的函数;问题的一个简单例子是:

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>(...);
}

我遇到的问题是:

  1. 在函数
  2. 中决定模板的内容
  3. 我不能在返回类型
  4. 上重载
  5. 我不想返回基类类型的EncodedMsg,因为我必须解码它后面的消息类型
  6. 有人能想到解决这个问题的方法吗?

4 个答案:

答案 0 :(得分:8)

您正试图以动态方式使用模板,这是不可能的。模板的类型必须在编译时知道,因此您无法根据一系列条件进行区分。

要在运行时更改类型,您需要来自类和继承的多态性。

答案 1 :(得分:3)

基本上,如果测试变量msg.qty不是编译时常量,那么这是不可能的。您必须了解模板可用于实现静态多态,而OOP(继承)可用于实现动态多态。换句话说,模板在编译时解析,而虚拟函数调用在运行时解析。您可以同时使用它们,但不能将它们用于相同的目的(即它们是互补的编程范例,每个范例都有自己的应用程序上下文)。

但是,如果可以,msg.qtyMsg类型的编译时常量(即Msg::qtyenumstatic 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}}。