5

次のようなポリモーフィッククラスのセットがあります。

class Apple {};
class Red : public Apple {};
class Green : public Apple {};

そしてそれらを比較する無料の機能:

bool operator==(const Apple&, const Apple&);
bool operator< (const Apple&, const Apple&);

コピー可能なラッパークラスを設計しています。これにより、ポリモーフィックな動作を維持しながら、クラスを使用RedGreenたり、STLマップのキーとして使用したりできます。

template<typename Cat>
class Copy
{
public:
    Copy(const Cat& inCat) : type(inCat.clone()) {}
    ~Copy() { delete type; }
    Cat* operator->() { return type; }
    Cat& operator*() { return *type; }
private:
    Copy() : type(0) {}
    Cat* type;
};

タイプはできるだけCopy<Apples>互換性があるようにしたいと思います。Apples上記のクラスに追加する必要のある関数は他にもいくつかありますがCopy、今のところ、次のように、の無料関数に取り組んでoperator==います。

template<typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e) {
    return *copy == e;
}

これが私のテストコードの一部です:

Red red;
Copy<Apple> redCopy = red;
Copy<Apple> redCopy2 = redCopy;
assert(redCopy == Red());

しかし、コンパイラは私に言っています

../src/main.cpp:91: error: no match for ‘operator==’ in ‘redCopy == Red()’

上記のoperator==を認識させるにはどうすればよいですか?答えは、暗黙の変換コードをどこかに追加することかもしれないと思いますが、どうしたらよいかわかりません。

4

3 に答える 3

9

テンプレートは次のように宣言されます

template <typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e)

は型であるredCopy == Red()ため、これは一致しません。したがって、コンパイラは2番目の引数の型として推定します。つまり=ですが、最初の引数の型はそうではありません(の型は)。Red()RedRedCatRedCopy<Red>redCopyCopy<Apple>

あなたが本当に表現したいのは

template <typename Cat>
bool operator==(const Copy<Cat>& copy, const something-that-derives-from-Cat& e)

これを行う最も簡単な方法は、2番目のテンプレートパラメータを追加することです。

template <typename Cat, typename DerivedFromCat>
bool operator==(const Copy<Cat>& copy, const DerivedFromCat& e)

もちろん、これは、DerivedFromCatが実際にCatから派生していることをコンパイラーに強制させるものではありません。これが必要な場合は、次を使用できますboost::enable_if

template <typename Cat, typename DerivedFromCat>
typename enable_if<is_base_of<Cat, DerivedFromCat>, bool>::type
operator==(const Copy<Cat>&, const DerivedFromCat& e)

しかし、それは少しやり過ぎかもしれません...

于 2011-06-06T20:02:24.547 に答える
3

しかし...どのように機能すると思いますか?テンプレート演算子を宣言しました

template<typename Cat>
bool operator==(const Copy<Cat>& copy, const Cat& e)

これは、RHSの型がLHSのテンプレート引数と同じであることを意味します(Catどちらの場合も)。しかし、あなたはそれがの場合に呼び出されることを期待しています

redCopy == Red()

はどこredCopyですかCopy<Apple>。どのように?

注:のテンプレート引数redCopyApple、ではなく、Redです。テンプレート演算子は、これらのタイプと一致しない可能性があります。

あなたがあなたのredCopy宣言を持っていた場合

Copy<Red> redCopy;

その後、オペレーターが機能します。またはあなたがした場合

redCopy == Apple()

オペレーターも同様に機能します。しかし、あなたがあなたのオリジナルのようなタイプを混ぜるとき

Copy<Apple> redCopy;
redCopy == Red();

それは単に機能しません。この場合のあなたの意図は何ですか?

于 2011-06-06T20:03:23.283 に答える
3

@ HighCommander4は、ここで何が問題なのかを説明しました。別の解決策は、の2番目のパラメーターの控除を無効にすることですoperator====次に、2番目のパラメーターのタイプは、 -operatorの最初の引数のみに基づいて推定されます。

template<typename T> struct identity { typedef T type; };

template<typename Cat>
bool operator==(const Copy<Cat>& copy, typename identity<Cat>::type const& e) {
    return *copy == e;
}

このようにすれば、どのタイプを表すのかという矛盾はなくCatoperator==期待通りに動作します。

于 2011-06-06T20:30:07.727 に答える