Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A general-purpose STLish contains()

I'm annoyed that STL containers don't have a, well, contains() method returning true if the container contains an element, false otherwise. So, I sat down and wrote this:

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

which works well enough for sets and maps, but not for vectors. Or lists. How should I proceed? Should I write an additional

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

and more specific code for other containers? Should I instead settle on the sub-optimal use of iterators to check element-by-element? I would really much rather not do that... perhaps I'm not noticing some relevant STL functionality?

like image 789
einpoklum Avatar asked Nov 12 '14 12:11

einpoklum


People also ask

What does a style contain?

A style is a set of formatting attributes that define the appearance of an element in the document. For example, a character style will contain font or font face attributes, while a paragraph style will contain paragraph alignment and line spacing attributes.

What is the purpose of style attribute?

The style attribute specifies an inline style for an element. The style attribute will override any style set globally, e.g. styles specified in the <style> tag or in an external style sheet. The style attribute can be used on any HTML element (it will validate on any HTML element.

What are the 3 ways to style in CSS?

There are three ways you can use to implement CSS into your HTML: internal, external, and inline styles.

What is style tag function?

The <style> tag in HTML helps us to modify our text, viewed in the page. This modification includes changing font size, font family, font color etc. Not only the texts but also we can change the style of a body ar part of a page.


2 Answers

I think one reason is for the absence of a std::contains returning a bool is that it is too easy for novice programmers to fall into the trap

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

and now you are doing twice the work you need.

It is simply idiomatic to write

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

If you insist on having a contains function, you could aim for the best of both worlds by returning a std::pair<bool, iterator> or a std::optional<iterator> (coming in a library fundamentals Technical Specification, or already present in Boost) that you can query like this:

if (opt = std::contains(my_container, some_element)) {
   // process *opt 
}
like image 88
TemplateRex Avatar answered Sep 22 '22 05:09

TemplateRex


If you intend to use this function only on STL containers, and if you further have no need to process the iterator returned by find, then yes, I would suggest you to write specific code for these containers. It is the most effective you can do.

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

The alternative would be to use metaprogramming and let the compiler determine whether the class contains a specific find function, but that would maybe be a bit overkill... Anyways, if want to go this way, you can read the recipes in this thread.

like image 44
davidhigh Avatar answered Sep 21 '22 05:09

davidhigh