boost::has_range_const_iterator replacement with std

67 views Asked by At

I have a big serialization library that rely on boost::has_range_const_iterator. The below code is part of a serialization library used in a game network.

template<typename T>
auto operator()(T const& vals) const -> typename std::enable_if<boost::has_range_const_iterator<T>::value>::type
{
    auto length = std::distance(std::begin(vals), std::end(vals));

    if (length > std::numeric_limits<uint16_t>::max())
        throw BadMessage("Length is too big to fit into length variable");

    (*this)(static_cast<uint16_t>(length));

    for (auto& val : vals)
        (*this)(val);
}

Is there some replacement in std for boost::has_range_const_iterator in the above context?

EDIT: What i have tried?

#include <iterator>
#include <list>
#include <vector>
#include <type_traits>
#include <iostream>

template <typename T>
struct has_const_iterator {
private:
    template <typename C>
    static std::true_type test(typename std::add_const<typename C::const_iterator>::type*);
    
    template <typename C>
    static std::false_type test(...);

public:
    static const bool value = decltype(test<T>(nullptr))::value;
};

int main() {
    // Example usage:
    std::vector<int> vec;
    if ( has_const_iterator<decltype(vec)>::value )
        std::cout << "Vector has a const iterator.";
    
    std::list<int> myList;
    if (!has_const_iterator<decltype(myList)>::value)
        std::cout << "List does not have a const iterator.";
    
    return 0;
}

it is good like this? Has anyone a better alternative ?

1

There are 1 answers

2
Ted Lyngmo On BEST ANSWER

You could probably use the concept std::ranges::input_range instead:

#include <ranges>

auto operator()(std::ranges::input_range auto&& vals) const {
    auto length = std::distance(std::ranges::cbegin(vals),
                                std::ranges::cend(vals));

    //...
}

You could also create a concept of your own to explicitly check if std::ranges::cbegin and cend are supported (although the standard range concept is most probably enough):

template <class T>
concept const_iterable = requires(T& t) {
    std::ranges::cbegin(t);
    std::ranges::cend(t);
};

You could also simplify your type trait somewhat:

template <class, class = void>
struct has_const_iterator : std::false_type {};

template <class T>
struct has_const_iterator<
    T, std::void_t<decltype(std::begin(std::declval<const T&>()))>>
    : std::true_type {};

// helper variable:
template <class T>
inline constexpr bool has_const_iterator_v = has_const_iterator<T>::value;