通用STLish包含()

时间:2014-11-12 12:03:59

标签: c++ algorithm stl containers idioms

我很恼火,如果容器包含一个元素{4},则STL容器不会返回contains()方法true。所以,我坐下来写下了这个:

false

适用于集合和贴图,但不适用于矢量。或列表。我该怎么办?我应该写一个额外的

template <typename C, typename E>
inline bool contains(const C& container, const E& element) {
    return container.find(element) != container.end();
}

以及其他容器的更具体代码?我是否应该继续使用迭代器的次优使用来逐元素地检查?我真的不愿意这样做......或许我没有注意到一些相关的STL功能?

2 个答案:

答案 0 :(得分:7)

我认为一个原因是没有std::contains返回bool,新手程序员很容易陷入陷阱

if (std::contains(my_container, some_element)) {
   auto it = std::find(begin(my_container), end(my_container), some_element);
   // process *it
}

现在你正在完成你需要的两倍工作。

编写

只是惯用语
auto it = std::find(begin(my_container), end(my_container), some_element);
if (it != end(my_container)) {
   // process *it
}

如果你坚持使用contains功能,那么你可以通过返回std::pair<bool, iterator>std::optional<iterator>来实现两全其美(在图书馆基础知识技术规范中,或者已存在于Boost中,您可以像这样查询:

if (opt = std::contains(my_container, some_element)) {
   // process *opt 
}

答案 1 :(得分:1)

如果您打算仅在STL容器上使用此函数,并且如果您还不需要处理find返回的迭代器,那么是的,我建议您为这些容器编写特定代码。这是你能做的最有效的。

template<typename ... Args> struct has_find {};
template<typename T> struct has_find<std::vector<T> > { static const bool value=false; };
template<typename T> struct has_find<std::deque<T> > { static const bool value=false; };
template<typename T, size_t I> struct has_find<std::array<T, I> > { static const bool value=false; };
template<typename T, typename U> struct has_find<std::map<T, U> > { static const bool value=true; };

//... and so on for the handful remaining containers

template<bool has_find>
struct contains_impl
{
    template <typename C, typename E>
    bool contains(const C& container, E&& element) const
    {
        return container.find(std::forward<E>(element)) != container.end();
    }
};

template<>
struct contains_impl<false>
{
    template <typename C, typename E>
    bool contains(const C& container, E&& element) const
    {
        return std::find(container.cbegin(), container.cend(), std::forward<E>(element)) != container.cend();
    }
};

template <typename C, typename E>
bool contains(const C& container, E&& element)
{
    return contains_impl<has_find<C>::value>().contains(container, std::forward<E>(element));
}

替代方法是使用元编程并让编译器确定该类是否包含特定的find函数,但这可能有点矫枉过正...... 无论如何,如果想要这样,你可以阅读this thread中的食谱。