#include <string>
#include <iostream>
#include <concepts>
//#include <type_traits>

template<typename Compound, typename Specified>
struct isEqual
{
    enum { equal = false };
};

template<typename Specified>
struct isEqual<Specified, Specified>
{
    enum { equal = true };
};

template<typename Compound, typename Specified>
concept same = isEqual<Compound, Specified>::equal;

//////////////////////////////////


template <typename Type, typename Ret>
concept ReturnType =
    requires(Type par)
    {
        { par[0] } -> std::same_as<Ret>;     // par[..] returns a Ret

    // no type constraints:
//        { par } -> isEqual<Ret>::equal;      // par returns a Ret
//        { par << 1 } -> isEqual<decltype(par << 1), Ret>::equal;

//        { par } -> same<Ret>;
//        { par } noexcept;

         {++par};
        // same as:
        // ++par;
    };

///////////////////////////////

struct XX
{
    void operator++()
    {};

    std::string  operator[](int idx) const
    {
        return std::string{"a"};
    }
};

template <typename Type, typename Ret>
    requires ReturnType<Type, Ret>
Ret ret(Type tp)
{
    return tp[0];
}

using namespace std;


int main()
{
    ret<XX, string>(XX{});
}
