Context
I want to check whether an element is present inside a container or not.
I would like to write a generic function which exploits the structure of the container.
In particular, the function should pick the method count() for those data structures which support that (e.g., std::set, std::unordered_set, ...).
In C++17 we can write something like:
#include <algorithm>
#include <iterator>
template <typename Container, typename Element>
constexpr bool hasElement(const Container& c, const Element& e) {
if constexpr (hasCount<Container>::value) {
return c.count(e);
} else {
return std::find(std::cbegin(c), std::cend(c), e) != std::cend(c);
}
}
All right! Now we need to implement hasCount<T> trait.
With SFINAE (and std::void_t in C++17) we can write something like:
#include <type_traits>
template <typename T, typename = std::void_t<>>
struct hasCount: std::false_type {};
template <typename T>
struct hasCount<T, std::void_t<decltype(&T::count)>> : std::true_type {};
This approach works quite well. For instance, the following snippet compiles (with previous definitions, of course):
struct Foo {
int count();
};
struct Bar {};
static_assert(hasCount<Foo>::value);
static_assert(!hasCount<Bar>::value);
Problem
Of course, I am going to use hasCount on STL data structure, such as std::vector, and std::set. Here the problem!
Since C++14, std::set<T>::count has a template overload.
Therefore static_assert(hasCount<std::set<int>>::value); fails!
That's because decltype(&std::set<int>::count) cannot be automatically deduced due to the overload.
Question
Given the context:
- is there a way to solve the automatic overload?
- if not, is there another way to write a better
hasCounttrait? (C++20 Concepts are not available).
External dependencies (libraries, such as boost) should be avoided.