2016-10-21 7 views
1

ここ数時間私の脳を壊していますが、このコードを実行しようとしているときにエラーが発生する理由はまだ分かりません。 は、いくつかの時間後、私は式にそれを絞り込むために管理:1つのテンプレート関数に2つの異なるコンパレータを渡すことができないのはなぜですか?

問題が発生する
pastryPrice() 

- あなたが見ることができるように、私は

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!"; } 
} 
仕分けの1つのテンプレート機能のための多数のコンパレータを構築しようとしています 私は5つのエラーを取得しています

、すべて同じ:

重大度コード説明プロジェクトファイルの行の抑制状態 エラーC2664「BOOLベーカリー:: pastryPrice ::演算子(const Pastry *、const pastry *)const ':引数1を' Deliver * 'から' const Pastry * 'に変換できません。ベーカリーc:\ program files(x86)\ microsoft visual studio 14.0 \ vc \ include \ xutility 809

そしてもう一つ:

重大度コード説明プロジェクトファイルの行の抑制状態 エラーC2056違法な表現ベーカリーC:\プログラムファイル(x86の)\マイクロソフトのVisual Studio 14.0 \ VCの\含める\ xutility 809

私が上記で書いた表現を外すと、コードはで正常に動作します - なぜ2つの異なるコンパレータを1つのテンプレート関数に渡すことができませんか?今

C2264は、1つの機能に互換性のないタイプのパラメータを渡すしようとしたときに発生するコンパイラエラーです。

しかし、Deliverコンパレータをオフにしたときに、Pastryも同様にコンパイルされました。互換性のないタイプは何ですか?

+4

これは、テンプレートがコンパイル時に評価されるのに対し、 'if'文は実行時に評価されるからです。したがって、常に関数呼び出しの1つが一致しません。 –

答えて

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); 
} 
+0

驚くばかり!ありがとうございます - 私はincomを想像したことがないでしょう – prowler

+0

*私はそれが互換性のない部分であるとは思わないでしょう...私はcreatin /いくつかの並べ替え関数を呼び出すことから回避しようとしました。 – prowler

+0

@prowler _ "私はcreatin /いくつかの並べ替え関数を呼び出すことから避けようとしました。" _そこからの利益はあまりありません。 –

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つの関数オブジェクトまたはlambdaをオーバーロードできます。 (完璧な転送は、varargsと同様に追加することができます...しかし、私はそれを簡単に保ちました)。

今、私たちは、単に:

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

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

using namespace std;を使用して停止します。


上記のコードは、2つの機能オブジェクトを一つにまとめたものです。 using A::operator()using B::operator()は、両方とも()を同じクラスに移動し、通常のメソッド呼び出しのオーバーロードルールを使用して呼び出したときにC++に指示するよう指示します。コードの残りの部分は、オーバーロードされている型を推定し、それらを移動構築するための接着剤です。

sortは、コンテナのタイプに基づいて、コンパイル時に決定されたタイプのオブジェクトを呼び出します(())。オーバーロードの解像度(コール時にsort以内)は、コンパイル時に比較するために右のボディを選択します。

このように、テクニックは、3つ以上のオーバーロード、関数ポインタ、および転送参照をサポートして拡張できます。 C++では、オーバーロード型で親の型を推定し、ファクトリ関数の必要性を排除するためにいくつかの作業を行うことができます。

+0

これは、OPのための少し過度かもしれません。しかし、それはとても美しく見えます。いくつかの修正を加えると、おそらく2つの過負荷を受け入れるだけでなく、 – Hayt

+0

@haytはいそれは簡単です。私はちょうどそれを短く甘く保った。 – Yakk

+0

@ヤクこれはいいですね!あなたはなぜ、コンストラクタ 'overload_t(A a、B b)の必要性を言うことができますか:A(std :: move(a))、B(std :: move(b)){}'? make-like関数でなければ 'return {};するだけです。 – vsoftco

関連する問題