12

2つのクラスがあると仮定します。最初のクラスはプリミティブ型(、、、boolなどintfloatを記述するためのもので、2番目のクラスは最初のクラスを拡張して複雑な型も書き込むためのものです。

struct Writer {
    virtual void Write(int value) = 0;
};

struct ComplexWriter : public Writer {
    template <typename TValue> void Write(const TValue &value) {
        boost::any any(value);
        Write(any);
    }
    //virtual void Write(int value) = 0; // see question below
    virtual void Write(const boost::any &any) = 0;
};

アイデアは、誰かがを呼び出すmyWriter.Write(someIntValue);と、intオーバーロードがテンプレート化されたメソッドよりも優先されるということです。

代わりに、私のコンパイラ(Visual C ++ 11.0 RC)は常にテンプレートメソッドを選択します。たとえば、次のコードスニペットWrote anyはコンソールに出力されます。

struct ComplexWriterImpl : public ComplexWriter {
    virtual void Write(int value) { std::cout << "Wrote an int"; }
    virtual void Write(const boost::any &any) { std::cout << "Wrote any"; }
};

void TestWriter(ComplexWriter &writer) {
    int x = 0;
    writer.Write(x);
}

int main() {
    ComplexWriterImpl writer;
    TestWriter(writer);
}

Write(int)クラスでメソッドを宣言すると、動作が突然変わりComplexWriterます(最初のスニペットのコメント化された行を参照)。次にWrote an int、コンソールに出力します。

これは私のコンパイラがどのように動作するべきですか?C ++標準では、同じクラスで定義された(基本クラスではなく)オーバーロードのみがテンプレート化されたメソッドよりも優先されると明示的に規定されていますか?

4

2 に答える 2

7

問題は、呼び出している時点でwriter.Write(x)コンパイラがComplexWriternot aを認識しているため、で定義されている関数(テンプレート関数とComplexWriterImpl関数) のみを認識していることです。 ComplexWriterboost::any

ComplexWriterを受け入れる仮想関数が含まれていないintため、で定義された int オーバーロードを呼び出す方法がありませんComplexWriterImpl

クラスに仮想オーバーロードを追加するとComplexWriter、コンパイラはクラスに整数オーバーロードがあることを認識し、ComplexWriterその実装を呼び出しますComplexWriterImpl

EDIT:ComplexWriterとWriterの間の継承を編集したので、より完全な説明があります:

サブクラスを作成してその中で関数を定義すると、引数の型に関係なく、基本クラスのその名前の関数はすべて非表示になります。

私が信じている using キーワードを使用すると、これを回避できます。

struct ComplexWriter : public Writer {
    template <typename TValue> void Write(const TValue &value) {
        boost::any any(value);
        Write(any);
    }
    using Writer::Write;
    virtual void Write(const boost::any &any) = 0;
};

詳細については、この FAQ エントリを参照してください: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

編集2:これが実際に問題を解決することを確認するためだけに:http://ideone.com/LRb5a

于 2012-06-07T12:31:27.553 に答える
2

ComplexWriter「インターフェイス」を介してオブジェクトにアクセスすると、コンパイラはWrite(int)そのクラスの定義を使用して関数呼び出しを解決しようとします。それができない場合は、基本クラスを検討します。

この場合、2 つの候補があります:Write(any)およびテンプレート化されたバージョンです。Write(int)この時点では利用可能 な明示的なものがないため、これら 2 つのオプションのいずれかを選択する必要があります。Write(any)は暗黙的な変換を必要としますが、テンプレート化されたバージョンはそうではありません。そのため、テンプレート化されたバージョンが呼び出されます (次に が呼び出されますWrite(any))。

Write(int)from を使用可能にするには、関数Writerをインポートします。Writer::Write

class ComplexWriter : public Writer
{
  using Writer::Write;
  // rest is as before
};
于 2012-06-07T12:48:01.730 に答える