You may not need to implement all of the member functions multiple times, but for some, you need to do it in different ways.
First, a type trait to check the existance of a lower_bound
member function
template<class T>
struct has_lower_bound_member_func {
struct no {};
template<class U = T> // on SFINAE match: `auto` is the type of the iterator
static auto check(int) ->
decltype(std::declval<U>().lower_bound(
std::declval<typename U::value_type>()));
static no check(long); // No lower_bound found, the type is `no`
// if the type is *not* `no`, the container has a lower_bound member function
static constexpr bool value = not std::is_same_v<decltype(check(0)), no>;
};
template<class T>
inline constexpr bool has_lower_bound_member_func_v =
has_lower_bound_member_func<T>::value;
A type trait to check if an iterator is a const_iterator
:
template<class It>
struct is_const_iterator {
using pointer = typename std::iterator_traits<It>::pointer;
static const bool value = std::is_const_v<std::remove_pointer_t<pointer>>;
};
template<class T>
inline constexpr bool is_const_iterator_v = is_const_iterator<T>::value;
Here are a few examples how those traits (and any future traits you add) could be used. You can use similar techniques for the other member functions that need special care:
template<class C>
class Numbers {
public:
using value_type = typename C::value_type;
template<class T = C>
auto lower(const value_type& val) {
if constexpr (has_lower_bound_member_func_v<T>) {
// a std::set<> will use this
return data.lower_bound(val);
} else {
// a std::vector<> will use this
return std::lower_bound(data.begin(), data.end(), val);
}
}
template<class ForwardIt>
auto replace(ForwardIt it, const value_type& val) {
if constexpr(is_const_iterator_v<ForwardIt>) {
// move the object out of the container by moving its node
// out of the set and reinsert if afterwards:
auto node_handle = data.extract(it);
node_handle.value() = val;
return data.insert(std::move(node_handle));
// or, if "it" is likely pointing close to the old value:
// return data.insert(it, std::move(node_handle));
} else {
*it = val; // not a const_iterator, assign directly
// You probably need to sort here:
std::sort(data.begin(), data.end());
it = std::lower_bound(data.begin(), data.end(), val);
// ... or do a clever std::rotate() to get it in place.
return it;
}
}
private:
C data;
};
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…