1

ここで数時間頭を悩ませていますが、このコードを実行しようとしたときにエラーが発生する理由がまだわかりません。しばらくして、次の式に絞り込むことができました。

pastryPrice()

これが問題の原因です-ご覧のとおり、ソートの1つのテンプレート関数に対して多数のコンパレータを作成しようとしています

    struct dialingAreaComp{
    inline bool operator()(const Deliver *d1, const Deliver *d2)const {
        return d1->getDialingArea() < d2->getDialingArea();
    }
};
struct pastryPrice {
    inline bool operator()(const Pastry *p1, const Pastry *p2)const {
        return p1->getPrice() < p2->getPrice();
    }
};
template<class T>
void sortCollection(T& collection)
{
    if ( typeid (collection) == typeid(vector <Deliver*>))
    {
        sort(collection.begin(), collection.end(), dialingAreaComp());
        printCollection(collection);
    }
    else if (typeid (collection) == typeid(vector <Pastry*>))
    {
        sort(collection.begin(), collection.end(), pastryPrice());
        printCollection(collection);
    }
    else { cout << "WRONG!"; }
}

5 つのエラーが表示されますが、すべて同じです。

重大度コード 説明 Project File Line Suppression State Error C2664 'bool Bakery::pastryPrice::operator ()(const Pastry *,const Pastry *) const': 引数 1 を 'Deliver *' から 'const Pastry *' に変換できません Bakery c :\プログラム ファイル (x86)\マイクロソフト ビジュアル スタジオ 14.0\vc\include\xutility 809

そしてもう1つ:

重大度コード 説明 Project File Line Suppression State Error C2056 illegal expression Bakery c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 809

上で書いた式を外すと、コードは問題なく動作します。1 つのテンプレート関数に 2 つの異なるコンパレータを渡せないのはなぜですか?

今:

C2264 は、互換性のない型のパラメーターを関数に渡そうとしたときに発生するコンパイラ エラーです。

しかし、Deliver 関数は機能し、Deliver コンパレータを外すと、Pastry もコンパイルされました...では、互換性のない型は何ですか?

4

2 に答える 2

5

あなたの問題は、どちらが取られるかに関係なく、両方のブランチがコンパイルされることです。

私はこれに別の方法でアプローチします。

template<class A, class B>
struct overload_t:A,B{
  using A::operator();
  using B::operator();
  overload_t(A a, B b):A(std::move(a)), B(std::move(b)){}
};
template<class A, class B>
overload_t<A,B> overload( A a, B b ){
  return {std::move(a),std::move(b)};
}

これにより、2 つの関数オブジェクトまたはラムダをオーバーロードできます。(可変引数と同様に、完全な転送を追加できます...しかし、私はそれを単純に保ちました)。

今、私たちは単純に:

auto comp=overload(dialingAreaComp{}, pastryPrice{});
using std::begin; using std::end;
std::sort( begin(collection), end(collection), comp );

コンパイラは正しい比較関数を選択します。私がそこにいた間、フラットアレイもサポートしました。

そして使用をやめるusing namespace std;


上記のコードが行うことは、2 つの関数オブジェクトの組み合わせを 1 つに融合することです。using A::operator()andusing B::operator()は両方を同じクラスに移動し、通常の()メソッド呼び出しのオーバーロード規則を使用して呼び出されたときに、C++ にどちらかを選択するように指示します。コードの残りの部分は、オーバーロードされている型を推測し、ムーブ コンストラクトするための接着剤です。

sort()コンテナーの型に基づいてコンパイル時に決定される型のオブジェクトを使用して呼び出します。オーバーロードの解決 (sort呼び出しの時点で) は、コンパイル時に比較する適切な本体を選択します。

したがって、2 つ以上のオーバーロード、関数ポインター、および転送参照をサポートすることで、この手法を拡張できます。C++17 では、オーバーロード型がその親型を推測するようにいくつかの作業を行うことができ、ファクトリ関数の必要性がなくなります。

于 2016-10-21T11:48:41.220 に答える
4

テンプレート化された関数はコンパイル時に評価され、関数呼び出しの 1 つが決して一致しないため、エラーが発生します。テンプレートの代わりに、単純な関数のオーバーロードを使用します。

void sortCollection(vector <Deliver*>& collection)
{
    sort(collection.begin(), collection.end(), dialingAreaComp());
    printCollection(collection);
}

void sortCollection(vector <Pastry*>& collection)
{
    sort(collection.begin(), collection.end(), pastryPrice());
    printCollection(collection);
}
于 2016-10-21T11:28:49.667 に答える