-1

I'd like to define a concepts that is true if

  1. t.ok(c) compiles and returns a bool, where t is a template parameter of type T and c is a "concrete" type of type C
  2. t.around(c) compiles and returns something that can be iterated over (the type of each element is C)

So far, I wrote the following mwe, but can't get my head around it to make it work.

#include <iostream>
#include <concepts>
#include <ranges>
#include <array>
#include <vector>

using namespace std;

struct Integ
{
    int val;  
};

template<class Cont, class T>
concept range_of = std::ranges::range<Cont> 
        && std::is_same_v<T, std::ranges::range_value_t<Cont>>;

template<class T, class Cont>
concept LookingRight = requires(const T& t, const Integ& i)
{
    { t.ok(i) } -> std::same_as<bool>; //ok if t.ok(i) compiles and returns bool
    { t.around(i) } -> range_of<Cont,Integ>; //ok it t.around(i) compiles and returns sth iterable
};


std::vector<Integ> filter(const auto& LookingRight lr, const Integ& i)
{ //probably a better way to filter with ranges
    std::vector<Integ> v;
    for(const Integ& ii : lr.around(i))
        if(lr.ok(ii))
            v.push_back(ii);
    return v;
}

struct Even
{
    bool ok(const Integ& i) const 
    { 
        return i.val % 2 == 0; 
    }   
    
    std::array<Integ,4> around(const Integ& i) const
    {
        return {Integ(i.val-2), Integ(i.val-1), Integ(i.val+1), Integ(i.val+2)};
    }
};

int main()
{
    Even e;
    for(auto i : filter(e, {0}))
        cout << i.val << " ";
    cout << endl;
}

I have some questions :

  • how to make it work, and what did I do wrong ?
  • why do I have to write -> std::same_as<bool> and I can't just write -> bool

I'm compiling with g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0. as g++ -std=c++20 -o mwe mwe.cpp

The compiler tells me that range_of<Cont, Integ> doesn't name a type (in the declaration of LookingRight). I also have syntax errors in the prototype of filter (I suspect they are there because LookingRight isn't properly defined)

R. Absil
  • 173
  • 6

1 Answers1

2

t.around(c) compiles and returns something that can be iterated over (the type of each element is C)

This is essentially two requirements. The result must be a range and the value type for that range must match a given type. std::ranges::range only answers the question "is it a range", not what it is a range over.

So you're going to need a concept that combines both questions:

template<typename R, typename T>
concept range_over =
  std::ranges::range<R> &&
  std::same_as<std::ranges::range_value_t<R>, T>;

You may need to apply remove_cv_t to T.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 2
    Not the latter, `value_type` is never cv-qualified. – Barry Oct 27 '22 at 19:51
  • Ok, I understand. I refactored my concepts to ```template concept range_of = std::ranges::range && std::is_same_v>;``` and `LookingRight` to `template concept LookingRight ... { t.around(i) } -> range_of; `, but so far, gcc tells me that `range_of` doesn't name a type (in the declaration of LookingRight). I also have syntax errors in the prototype of `filter` (I suspect they are there because LookingRight isn't properly defined) – R. Absil Oct 28 '22 at 05:15
  • ... and I edited the original post so include the modifications mentioned above – R. Absil Oct 28 '22 at 09:56
  • (still doesn't work) – R. Absil Oct 28 '22 at 11:59