2
\$\begingroup\$

I wrote simple generic function to check if any STL container has an element. It seems work fine. I have tested it with VC++, GCC and Clang compilers. It works perfectly.

How can I improve it further.

#include <iostream>
#include <algorithm>
#include <utility>
#include <map>
#include <set>
#include <vector>
#include <array>
#include <type_traits>

// Detect if container has C::find
template <typename C> decltype(std::declval<C>().find(0), std::true_type{}) test(int);
template <typename C> std::false_type test(...);
template <typename C> using has_find = decltype(test<C>(0));

// Based on std::conditional
template <bool B, typename T, typename F>
struct conditional_impl
{
    constexpr static F pick(T&& , F&& f)
    {
        return std::forward<F>(f);
    }
};

template <typename T, typename F>
struct conditional_impl<true, T, F>
{
    constexpr static T pick(T&& t, F&&)
    {
        return std::forward<T>(t);
    }
};

template <bool B, typename T, typename F>
auto conditional(T&& t, F&& f)
{
    return conditional_impl<B,T,F>::pick(std::forward<T>(t), std::forward<F>(f));
}

// one for all and all for one
template <typename C, typename T>
auto contains(const C& container, const T& key)
{
    static auto first = [] (auto&& c, auto&& k)
    {
        return c.end() != c.find(k);
    };

    static auto second = [] (auto&& c, auto&& k)
    {
        return c.end() != std::find(c.begin(), c.end(), k);
    };

    auto op = conditional<has_find<C>::value>(first, second);

    return op(container, key);
}

int main()
{
    std::cout << std::boolalpha;

    std::array<int, 3> a = {{ 1, 2, 3 }};
    std::cout << contains(a, 0) << "\n";
    std::cout << contains(a, 1) << "\n\n";

    std::vector<int> v = { 1, 2, 3 };
    std::cout << contains(v, 0) << "\n";
    std::cout << contains(v, 1) << "\n\n";

    std::set<int> s = { 1, 2, 3 };
    std::cout << contains(s, 0) << "\n";
    std::cout << contains(s, 1) << "\n\n";

    std::map<int, int> m = { { 1, 1}, { 2, 2}, { 3, 3} };
    std::cout << contains(m, 0) << "\n";
    std::cout << contains(m, 1) << "\n";
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Nice toy! Took me a while to wrap my head around it. It looks ok. The only thing I was thinking about is why not to use std::enable_if as it is much simpler.

#include <iostream>
#include <algorithm>
#include <utility>
#include <map>
#include <set>
#include <vector>
#include <array>
#include <type_traits>

// Detect if container has C::find
template <typename C> decltype(std::declval<C>().find(0), std::true_type{}) test(int);
template <typename C> std::false_type test(...);
template <typename C> using has_find = decltype(test<C>(0));

template <typename C, typename T>
typename std::enable_if<has_find<C>::value, bool>::type contains(const C& container, const T& key) {
    return c.end() != c.find(k);
}

template <typename C, typename T>
typename std::enable_if<!has_find<C>::value, bool>::type contains(const C& container, const T& key) {
    return c.end() != std::find(c.begin(), c.end(), k);
}

int main()
{
    /* */
}
\$\endgroup\$
2
  • \$\begingroup\$ thanks for answering, i think i had to mention it earlier. i was trying to implement "static_if" that will compile in all famous compilers. but sure std::enable_f makes code nicer. \$\endgroup\$
    – MORTAL
    Commented Jun 17, 2016 at 9:18
  • \$\begingroup\$ @MORTAL Ok. I had an impression like you are implementing it yourself just for the sake of learning/fun/whatever. In that case I have can't help as your code looks good to me. \$\endgroup\$
    – Jan Korous
    Commented Jun 17, 2016 at 9:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.