2012-02-07 7 views
1

タイトルが不適切である場合は、自由に書き換えてください。私はSTLのfindとfind_ifアルゴリズムの上にラッパーを考え出しています。これは今私が持っているものです。C++で述語と値を取るメソッドをオーバーロードする方法

template<typename Type, size_t SIZE> 
int IndexOf(const Type(&arr)[SIZE], const Type& val) 
{ 
    return IndexOf(arr, arr + SIZE, val); 
} 

template<typename Iter, typename Type> 
int IndexOf(Iter first, Iter last, const Type& val) 
{ 
    auto index = find(first, last, val); 

    if (index != last) 
    { 
     return distance(first, index); 
    } 
    return -1; 
} 


template<typename Type, size_t SIZE, typename Pred> 
int IndexOf(const Type(&arr)[SIZE], Pred pred) 
{ 
    return IndexOf(arr, arr + SIZE, pred); 
} 


template<typename Iter, typename Pred> 
int IndexOf(Iter first, Iter last, Pred pred) 
{ 
    auto index = find_if(first, last, pred); 

    if (index != last) 
    { 
     return distance(first, index); 
    } 
    return -1; 
} 

以下の使用法ではあいまいなオーバーロードが発生することはありません。

vector<string> names; 
names.push_back("Jagan"); 
names.push_back("Gagan"); 
names.push_back("Magan"); 
names.push_back("Pagan"); 
names.push_back("Vagan"); 

std::cout << "Index of (Gagan)" << IndexOf(begin(names), end(names), 
              [](const string& name) 
              { 
             return name == "Gagan"; 
              }); 

上記の使用例は簡潔にするためのものです。

+0

'constの型名をお試しくださいIter :: value_type&val'を2回目のオーバーロードで実行します。 –

+0

@Kerreck SB、-1は間違いでした。完全にテストしていませんでした。論理よりもコンパイルの問題を見ていました。 – Jagannath

+0

あなたのインデックスに 'std :: size_t'を使うことを検討してください。 – pmr

答えて

3

stdlibと同じようにします。オーバーロードしないでください。例えば、stdlibはある範囲内の何かを検索するための2つの関数を提供しています。

名前はfind(「find the value!」など)、もう1つはfind_if(「述語がtrueを返すと見つけた」など)という名前です。


別のオプションは、(C++ 11と表現SFINAEを使用して)いくつかのSFINAEの策略を採用するかもしれない:*first == valueが有効でない場合

template<class T> 
T create(); 

template<class InIt, class T> 
auto find(InIt first, InIt last, T const& value) 
    -> decltype((*first == value), create<InIt>()) 
{ 
    // ... 
} 

この機能は、過負荷セットから削除されます式(通常は、述部をコンテナーに保管したり、同じ述部で検索したりしません)。

decltype, create<InIt>()は、返品タイプをInItとします。 createは評価されていないコンテキストでのみ使用されるため、定義されていないため、定義を必要としません(実際にこのようなオブジェクトを実際に構築する方法を推測する必要はありません)。 InIt)。私はfirst代わりcreate<InIt>()を使用した場合は、この機能は削除されます

template<class Init, class Pred> 
auto find(InIt first, InIt last, Pred pred) 
    -> decltype((pred(*first)?0:0), create<InIt>()) 
{ 
    // ... 
} 

ローカル変数への参照を返すしているので、戻り値の型は、良いやや驚くべきではないだろうInIt&をしてきたでしょうオーバーロードセットからpred(*first)が有効な式でない場合、すなわちpredvalue_typeInItのパラメータとして使用しません。 predoperator()の戻り値の型が、boolに明示的に変換できない場合は、3進論理演算子?:を使用してテストし、さらに削除されます。再び、, create<InIt>()は、戻り値の型を返す関数を与えるために使用されます。

具体的なケースについては、small live example on Ideoneです。リテラル0は既にタイプintであるため、ここではcreate<int>()を使用しなかったことに注意してください。ここで

+0

これは 'InIt&'を返します。重要ではないかもしれません。 –

+0

ダン三元演算子... – Xeo

+0

ありがとうございます。これは参考になります。 – Jagannath

0

は、2つのオーバーロードを明確にするために、やや生意気な方法です:イテレータの値型は引数から構成することができるならば、我々はfindを選んで、それ以外の我々は、述語として引数を扱う:

#include <algorithm> 
#include <iterator> 
#include <type_traits> 

template<typename Iter> 
int IndexOf(Iter first, Iter last, typename std::iterator_traits<Iter>::value_type const & val) 
{ 
    auto index = std::find(first, last, val); 
    return index != last ? std::distance(first, index) : -1; 
} 

template<typename Iter, typename Pred> 
typename std::enable_if<!std::is_constructible<typename std::iterator_traits<Iter>::value_type, Pred>::value, int>::type 
IndexOf(Iter first, Iter last, Pred pred) 
{ 
    auto index = std::find_if(first, last, pred); 
    return index != last ? distance(first, index) : -1; 
} 
関連する問題