如何在c ++中重载谓词与值的方法

时间:2012-02-07 22:22:06

标签: c++ stl

如果标题不合适,请随时重新标注。我试图在STL中找到find和find_if算法之上的包装器。这就是我现在所拥有的。

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";
                                          }); 

以上示例用法仅用于简洁。

2 个答案:

答案 0 :(得分:3)

按照stdlib的做法:不要超载。例如,stdlib提供了两个函数,可以让您搜索范围内的某些内容。

一个名为find(如“找到该值!”),另一个名为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是为其提供InIt的返回类型。 create未定义,因为它只会在未评估的上下文中使用,因此不需要定义(这使生活更容易,我们不必猜测我们如何实际构建这样的对象。我们只需取类型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_type InIt作为参数。如果pred的{​​{1}}的返回类型未明确转换为operator(),则会通过使用bool(三元逻辑运算符)进行测试。同样,?:用于为函数提供, create<InIt>()返回类型。

这是针对您具体案例的small live example on Ideone。请注意,我在此处未使用InIt,因为文字create<int>()已经是0类型。

答案 1 :(得分: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;
}