2016-07-29 6 views
0

仮想関数でなければならないテンプレート関数の回避策に関する質問は、私の問題に役立つ何かを見つけることができませんでしたが、ここではかなり一般的です。need a virtual template member workaroundテンプレート戻り値の回避策を使用した仮想テンプレート関数

提案されたアプローチは、タイプ消去を使用して、きれいで簡単な解決策を導く。しかし、visit()メソッドから値を返す必要がある場合はどうすればよいですか? OPはすでに彼の質問でこの側面を持っていましたが、彼は決してその結果を使用しなかったので、解決策では無視されました。我々はまだaccept()も型消去のトリックを適用した後、テンプレート化する必要が

template <typename T> 
class BaseVisitor { 
    public: 
    BaseVisitor(); 
    T visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
} 


class BaseVisited { 
    BaseVisited(); 
    template <typename T> 
    virtual T accept(BaseVisitor<T> *visitor) { return visitor->visit(this); }; 
    virtual ~BaseVisited(); 
} 

は今、代わりにこのコードを想像してみてください。その他のアイデアは?

注:Tは任意の基底型(int、stringなど)を表すことができるので、SOの答えのいくつかで示唆されているように、戻り値には基本クラスを使用できません。あなたは基本的に2つの選択肢があり

+0

あなたがクローズ型システム(例えば、 'のstd ::バリアント<>')と型消去(例えば、 '後押し:: any'、'ボイド大丈夫じゃない場合* ')、おそらく唯一の選択は' return T;の代わりに 'T(...);をスローすることです。 – lorro

答えて

1

  1. std::anyまたはその前身boost::anyのように、accept()のための一般的な戻り値の型を提供します。または、有限の数の可能な戻り値型がある場合は、std::variant/boost::variantです。このようにして、メンバ関数はテンプレートである必要はありませんが、呼び出し元はその処理を知る必要があります。

  2. Visitorオブジェクトに型指定された結果を格納します。あなたはそれを返す代わりにそれを格納しなければなりませんが、少なくともあなたはその型を保持することができます。これはVisitor Patternを使用して処理できます。さまざまな結果タイプを持つ訪問者を持つことができます。彼らは、内部でそれらを格納:

    // a void visitor 
    struct ShapePrinter : IShapeVisitor 
    { 
        void visit(const Square&) override { std::cout << "Square"; } 
        void visit(const Circle&) override { std::cout << "Circle"; } 
    }; 
    
    // a double visitor 
    struct ShapePerimeterComputer : IShapeVisitor 
    { 
        void visit(const Square& square) override { perimeter = 4. * square.sideLength; } 
        void visit(const Circle& circle) override { perimeter = 2. * M_PI * circle.radius; } 
    
        double perimeter = 0.; 
    }; 
    
+0

第2番は読み込みまでロックしていない限り、マルチスレッド環境で素晴らしい副作用があります。 – lorro

+0

私はC++ 17やBoostを使うことはできませんが、実際にはここで助けてくれるAnyクラスがあります。私はそれを試して、うまくいくかどうかを見てみましょう。 –

関連する問題