2012-02-07 71 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; 
}