1

Given concept test which has a function that takes an input range.

template <class T>
concept test = requires(T t, archtypes::Input_Range<T> t_range)
{
    { t.count(t_range) } -> std::same_as<int>;
};

This archtype allows for the count function to be a template member function.

struct Counter1
{
    template<std::ranges::input_range Range>
    int count(const Range&);
}
static_assert(test<Counter1>); // passes

Now this satisfies the concept. But I would like this to fail, since this range can be any input range not just input range with int.

Only this should pass

struct Counter2
{
    template<std::ranges::input_range Range>
    requires std::is_same_v<int,std::ranges::range_value_t<Range>>
    int count(const Range&);
}
namespace archetypes
{
    // private, only used for concept definitions, NEVER in real code
    template <class T>
    class InputIterator
    {
    public:
        InputIterator();
        ~InputIterator();
        InputIterator(const InputIterator& other);
        InputIterator(InputIterator&& other) noexcept;
        InputIterator& operator=(const InputIterator& other);
        InputIterator& operator=(InputIterator&& other) noexcept;


        using iterator_category = std::input_iterator_tag;
        using value_type = T;
        using reference = T&;
        using pointer = T*;
        using difference_type = std::ptrdiff_t;

        bool operator==(const InputIterator&) const;
        bool operator!=(const InputIterator&) const;
        reference operator*() const;
        InputIterator& operator++();
        InputIterator operator++(int);
    };
    
    template <class T>
    struct Input_Range
    {
        Input_Range(const Input_Range& other) = delete;
        Input_Range(Input_Range&& other) = delete;
        Input_Range& operator=(const Input_Range& other) = delete;
        Input_Range& operator=(Input_Range&& other) = delete;
        ~Input_Range();

        using iterator = InputIterator<T>;

        iterator begin();
        iterator end();
    };
}

I can't think of any way to change the concept or archtype so the Counter1 would fail, but Counter2 would pass.

freeman23
  • 11
  • 1

1 Answers1

0

Now this satisfies the concept. But I would like this to fail, since this range can be any input range not just input range with int.

This requirement represents an improper use of a concept. Your job as the writer of a concept is to express what interface you expect the user to provide (and thereby exactly what interface you will be using). The user's job as the implementer of some set of types that fulfill that concept is to provide an interface that syntactically and semantically matches the concept.

Your code will only provide a range of integers, per your concept. The user may allow this function to take a range of other things. That is their prerogative, and you should not attempt to interfere with this. Your code will still work just fine against such a type, so there is no reason to prevent this.

Your job is not to force a type to only provide the interface you asked for. Just as std::ranges::sort should not prevent a user from providing a contiguous range just because it only asked for a random-access range.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Okay... I guess you're right about that, can't think of any arguments against it. But still I'm curious how this can be done. – freeman23 May 31 '21 at 14:42