2012-02-07 26 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'在第二個過載中。 – 2012-02-07 22:25:06

+0

@Kerreck SB,-1是一個錯誤。沒有測試完整。看看編譯問題,而不是邏輯。 – Jagannath 2012-02-07 22:39:32

+0

考慮爲你的索引使用'std :: size_t'。 – pmr 2012-02-07 23:15:53

回答

3

像stdlib一樣做:不要超載。例如stdlib提供了兩個函數,可以讓你搜索範圍內的東西。

其中一個被命名爲find(例如「find that value!」),另一個被命名爲find_if(如「如果謂詞返回true!」,則返回)。


另一種選擇可能是採用某種SFINAE弄虛作假(使用C++ 11和表達SFINAE):

template<class T> 
T create(); 

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

該功能將從過載集中刪除,如果*first == value不是有效的表達式(您通常不會將謂詞存儲在容器中,並使用相同的謂詞進行搜索)。

, create<InIt>()decltype是給它一個返回類型InItcreate是未定義的,因爲它只會在未經評估的上下文中使用,因此不需要定義(這使得生活更簡單,我們不必猜測如何實際構建這樣的對象。 InIt)。如果我使用的first代替create<InIt>(),返回類型會一直InIt&,這將是略微令人驚訝的並不好,因爲你是一個參考返回一個局部變量

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

此功能將被刪除如果pred(*first)不是一個有效的表達式,即pred不將value_typeInIt作爲參數,如果predoperator()的返回類型沒有明確轉換爲bool,則通過使用?:(即三元邏輯運算符)進行測試,它將被刪除。同樣,, create<InIt>()用於賦予函數InIt返回類型。

這是您的具體情況的small live example on Ideone。請注意,此處我沒有使用create<int>(),因爲字面值0已屬於int類型。

+0

現在它返回'InIt&'。可能會或可能不重要。 – 2012-02-07 22:38:05

+0

該死的三元操作員... – Xeo 2012-02-07 22:40:36

+0

謝謝。這很有幫助。 – Jagannath 2012-02-07 22:45:36

0

這裏來澄清對兩個重載有點厚臉皮的方式:如果迭代器的值類型可以通過以下參數來構建,我們選擇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; 
}