通用STLish包含()

ein*_*ica 5 c++ algorithm containers stl idioms

我很生气,如果容器包含一个元素,STL容器没有contains()返回true的方法,false否则.所以,我坐下来写下这个:

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

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

template <typename T>
inline bool contains(const vector<T>& container, const T& element) {
    std::find(vector.begin(), vector.end(), item) != vector.end()
}
Run Code Online (Sandbox Code Playgroud)

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

Tem*_*Rex 7

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

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

现在你做了两次你需要的工作.

写作只是惯用语

auto it = std::find(begin(my_container), end(my_container), some_element);
if (it != end(my_container)) {
   // process *it
}
Run Code Online (Sandbox Code Playgroud)

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

if (opt = std::contains(my_container, some_element)) {
   // process *opt 
}
Run Code Online (Sandbox Code Playgroud)

  • 但是(2):语义是关闭的.我希望我的程序读起来像"如果my_container包含元素some_element然后做一些事情." - 我不希望它读作"在my_container中找到some_element的位置;现在,如果你没有发现它是一个无效的位置,那么它必须是它存在的情况,所以让我们做点什么." (3认同)

dav*_*igh 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));
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用元编程并让编译器确定该类是否包含特定find函数,但这可能有点矫枉过正...无论如何,如果想这样做,您可以阅读此线程中的食谱。