2011-02-07 27 views
0

さまざまなテンプレート型を作成できる関数があります。問題の簡単な例は次のようになります。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. は、私はそれは
に、後にあるメッセージの種類をデコードする必要がありますようEncodedMsgの基底クラス型を返すようにしたくありません3210

誰もこれを回避する方法を考えることができますか?

答えて

8

テンプレートを動的に使用しようとしていますが、これは不可能です。テンプレートの型はコンパイル時に認識されなければならないため、一連の条件に基づいて区別することはできません。

実行時に型を変更するには、クラスと継承の多型が必要です。

0

このアプローチは、あなたが(私が疑われるので、例えば、EncodedMessage<long>EncodedMessage<short>EncodedMessagesで動作するいくつかの方法、に通行可能でなければなりません両方)を促進したい場所をどこにでもEncodedMessageを使用することはできません。

あなたが求めていることは、トリックで行うことができますが、あなたのアーキテクチャを再考することをお勧めします。

すべてのメッセージ数に使用できる場合はEncodedMessage<long>に固執し、TheOnlyPossibleEncodedMessageとタイプすることができます。

3

基本的に、テスト変数msg.qtyがコンパイル時定数でない場合、これは不可能です。静的多型を達成するためにテンプレートを使用できる一方で、動的多型を達成するためにOOP(継承)を使用できることを理解する必要があります。つまり、実行時に仮想関数呼び出しが解決されている間は、コンパイル時にテンプレートが解決されます。両方を同時に使用できますが、同じ目的で使用することはできません(つまり、それぞれ独自のアプリケーションコンテキストを持つ補完的プログラミングパラダイムです)。あなたは、しかし、(enumまたはstatic constとして、すなわちMsg::qty)タイプMsgのコンパイル時定数であることをmsg.qtyを得ることができれば

は、その後、あなたは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>(...); }; 

しかし、あなたが判断できた場合に、特定のクラスのメッセージのために、どのようなテンプレートのインスタンス化EncodedMsgに使用する、クラスの入れ子になったのtypedefとして定義する多くの方が簡単です次のようにメッセージは、あなたのエンコード機能を定義します。

template <class Msg> 
Msg::encoded_type* encode(const Msg& msg) { return new Msg::encoded_type(...); }; 

また、あなたが変更できないメッセージクラスを持っている場合は、ネストされたのtypedefを定義するために(そのような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オブジェクトへのポインタの格納))。そして、それが多形的な代替案と同じくらい素晴らしいと効率的ではありません。

1

1)関数の戻り値の型をオーバーロードすることはできませんが、関数 をオーバーライドしてポインターを渡すことができます。 2)

2)基本的には、問題に対する別の設計アプローチを使用する必要があります。 基本クラスで仮想インターフェイスを使用すると、メソッドが正しく クラスを返します1つは適切な仮想関数を呼び出すだけです。あなたはEncodedMsgBaseから派生している限り、EncodedMsg_whateverとなる基本クラス(EncodedMsgBase)を返します。必要に応じて、基本クラスからテンプレートを作成することができます。

もっと複雑なシナリオでは、これは「どのように私がC++でファクトリを作成するか」の問題に終わります。人々は通常、「仮想コンストラクタイディオム」を実装する基本クラスを渡すことによって、これを回避します。

Cをチェック++その詳細はFAQ:

http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.8

また、静的型付けを使用することにより、1つは、多くのトラブルを避けることができることを心に留めておく:)

関連する問題