c++iteratorc++-conceptsduck-typingconcept

Troubleshooting Iterator-Like Concept Definition for Pointer-Like Iterators in C++


I am new in C++20. I’ve been refining a C++ concept, IteratorLike, designed to encapsulate the behavior of iterators. The concept checks for element access, iterator advancement, and end-of-sequence comparison. Here’s the concept definition:

template <typename Iter, typename ValueType, typename AccessFn, typename NextFn>
concept IteratorLike = std::invocable<AccessFn, Iter>
    && std::invocable<NextFn, Iter>
    && std::equality_comparable<Iter>
    && std::same_as<std::remove_cvref_t<std::invoke_result_t<AccessFn, Iter>>, ValueType>
    && std::same_as<std::remove_cvref_t<std::invoke_result_t<NextFn, Iter>>, Iter>;

But I’m not sure how to apply the definition of an iterator with pointer semantics to this concept, or perhaps there might be shortcomings in my definition of the IteratorLike concept.

I would appreciate any suggestions for improvement.


The use of decltype with the overloaded operators is causing a compilation error:

static_assert(
    IteratorLike<
        std::vector<int>::iterator,
        int,
        decltype(&std::vector<int>::iterator::operator*),
        decltype(&std::vector<int>::iterator::operator++)
    >
);

The compiler returns: ‘error: ‘decltype’ cannot resolve address of overloaded function.’


Solution

  • ‘error: ‘decltype’ cannot resolve address of overloaded function.’

    There are two operator++ overloads. One for pre-increment (++it) and one for post-increment (it++). When you take the address of std::vector<int>::iterator::operator++ the compiler has no idea which one you want so you need to help it.

    Example:

    // taking the address of the pre-increment operator++
    std::vector<int>::iterator& (std::vector<int>::iterator::*preinc)() =
        &std::vector<int>::iterator::operator++;
    
    // taking the address of the post-increment operator++
    std::vector<int>::iterator (std::vector<int>::iterator::*postinc)(int) =
        &std::vector<int>::iterator::operator++;
    
    static_assert(IteratorLike<std::vector<int>::iterator, int,
                               decltype(&std::vector<int>::iterator::operator*),
                               decltype(preinc)>);
    

    Note though that not all iterators are of class type. A std::vector<T>::iterator may just be a plain pointer, and if so, you can't take the address of its operator* or any of operator++.