c++c++20c++-concepts

Why does my Container concept fail for const std::list<double> due to begin() and end() not satisfying the return-type requirements?


I am trying to define a Container concept in C++ that validates standard library containers, including std::list. However, the concept fails for const std::list<double> because the begin() and end() functions in std::list do not meet the expected return types for iterators in my concept. Specifically, they return iterator for non-const objects and const_iterator for const objects, and my current concept does not account for this distinction properly. How can I modify my concept to handle these cases correctly?

I tried adding checks using std::as_const but the issue persists. I expected the concept to pass for both const and non-const containers but need help addressing this mismatch.

template <typename C>
concept Container = requires(C c, const C cc) {
    typename C::value_type;
    typename C::reference;
    typename C::const_reference;
    typename C::iterator;
    typename C::const_iterator;
    typename C::difference_type;
    typename C::size_type;

    { c.begin() } -> std::convertible_to<typename C::iterator>;
    { c.end() } -> std::convertible_to<typename C::iterator>;

    { c.cbegin() } -> std::convertible_to<typename C::const_iterator>;
    { c.cend() } -> std::convertible_to<typename C::const_iterator>;

    { cc.begin() } -> std::convertible_to<typename C::const_iterator>;
    { cc.end() } -> std::convertible_to<typename C::const_iterator>;

    requires std::is_copy_constructible_v<C>;
};

Solution

  • One just needs to test the const-removed version of C:

    concept Container = requires(typename std::remove_const_t<C> c, const C cc) {
        ... /* keep the same */ ...
    };
    

    See https://godbolt.org/z/b4aMPdoWM