5

テンプレート引数として指定されたクラスに対してアクションを実行するテンプレート化されたクラスがあります。一部のクラスでは、機能を 1 つのクラスに「グループ化」して、呼び出し元を簡単にしたいと考えています。実際、コードは次のようになります (名前は変更されています)。

template<typename T>
class DoSomeProcessing
{
public:
   process(T &t);
};

class ProcessingFrontEnd : public DoSomeProcessing<CustomerOrder>, public DoSomeProcessing<ProductionOrder>
{
};

問題は、引数として CustomerOrder を指定して ProcessingFrontEnd::process を呼び出すと、コンパイラがそれについて文句を言うことです。

小規模なテスト アプリケーションで問題を再現しようとしました。これはコードです:

#include <vector>

class X : public std::vector<char>
        , public std::vector<void *>
{
};

int main(void)
{
X x;
x.push_back('c');
return 0;
}

実際、これをコンパイルすると、Microsoft の VS2010 コンパイラは次のエラーを返します。

test.cpp
test.cpp(11) : error C2385: ambiguous access of 'push_back'
        could be the 'push_back' in base 'std::vector<char,std::allocator<char> >'
        or could be the 'push_back' in base 'std::vector<void *,std::allocator<void *> >'
test.cpp(11) : error C3861: 'push_back': identifier not found

このテスト アプリケーションをさまざまな型 (char+void*、double+void*) と呼び出しのさまざまな引数 ('c'、3.14) でテストしましたが、エラー メッセージは常に同じです。

これを VS2005 と VS2010 でテストしましたが、常に同じエラーが発生します。

コンパイラが呼び出す正しい関数を判断できないのはなぜですか? これがコンパイラを混乱させるのはなぜですか? それとも、Microsoft コンパイラの単なるバグですか?

編集: クラスに 2 つの push_back メソッドを明示的に追加すると、次のようになります。

class X : public std::vector<char>
        , public std::vector<void *>
{
public:
   void push_back(char c) {}
   void push_back(void *p) {}
};

コンパイラはもう文句を言いません。したがって、これらのメソッドを使用すると、文字と void-pointer を明確に区別できます。2 つの push_back メソッドが親から継承されている場合、なぜ彼はこれを行うことができないのでしょうか?

4

3 に答える 3

4

これは仕様によるものです。これらはオーバーロードされた関数ではないため、コンパイラはオーバーロードされた関数を解決しようとはしていません。標準はそれについて非常に明確です(10.2.2を参照)。同じ名前が 2 つの異なるベースで見つかった場合、呼び出しで正しく解決できたとしても (つまり、あなたの場合)、あいまいです。異なるクラスの同じ名前の関数は、通常、まったく異なる目的を持っているため、引数に基づいてそれらを選択するべきではありません。それを許可しない正当な理由はたくさんありますが、ここではその 1 つを示します。

クラス C が A と B から派生し、これら 2 つの基本クラスが 2 つの異なるライブラリから派生したとします。B の作成者がクラスに新しい関数を追加すると、呼び出しが A::foo() から B::foo() にリダイレクトされ、後者の方が適している場合は、ユーザーのコードが壊れる可能性があります。

2 つの関数を 1 つのクラスの一部である場合と同じように処理する場合は、派生クラスで宣言を使用するのが最善の方法です。追加するだけ

using std::vector<char>::push_back;
using std::vector<void *>::push_back;

クラスXの宣言に。

于 2010-08-24T11:45:20.803 に答える
2

クラス間でのオーバーロードを禁止するC++オーバーロードルールに違反していると思います。テンプレートクラスがそれぞれ独自のメンバーを持つ2つの別個のクラスである場合、同じ結果が得られprocess(CustomerOrder)ますprocess(ProductionOrder)

回避策は、派生クラス内の明示的なusingステートメントであり、各テンプレート基本クラスから各オーバーロードを取得します。

于 2010-08-24T11:45:06.407 に答える
-2

コンパイラは、どのプロセスを呼び出したいかをどのように知ることになっていますか? 2 つのオプションがあります。両方が必要ですか、どちらかが必要ですか?

派生クラスでプロセスをオーバーライドする必要があります。

于 2010-08-24T11:11:52.090 に答える