#std::same_as with references

42 messages · Page 1 of 1 (latest)

pastel vale
#

Working on a concept like so:

template<typename PointType, typename NumberType>
concept Pointlike = requires(PointType point) {
    requires std::derived_from<PointType, Point<NumberType>>;
    { point.x } -> std::convertible_to<NumberType>;
    { point.y } -> std::convertible_to<NumberType>;
    requires arithmetic<NumberType>;
};

Which works, but I would like to replace std::convertible with something like std::same_as, but I'm hitting problems with an int& bubbling up to compare with int which is not allowed, obviously.

I'm not sure the best way to allow for this comparison google says maybe std::decay or std::remove_cvref but I can't get the syntax to work right. Or am I maybe calling the method wrong someplace?

wicked iceBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

pastel vale
#
drowsy vale
#

make a helper concept i guess ```cpp
template<typename T, typename U>
concept SameAsRemoveCVRef = std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;

fickle stirrup
pastel vale
#

if possible, I'd like to enforce immutability, but that seems difficult without adding get members which doesn't feel appropriate for such a simple type, so I guess I'll leave that to user to enforce

pastel vale
drowsy vale
#

what did you try

pastel vale
#

I am somewhat worried/currious ... oh wait no know why the reference cropped up.

#
template<typename Point, arithmetic N, typename Derived>
requires Pointlike<Point, N>
struct BoundsBase
{
    Point min, max;

    constexpr BoundsBase()  = default;
    constexpr BoundsBase(Point min, Point max) : min(min), max(max) {}
}

assignment through the concept happens here, so I guess that's where my reference comes from

fickle stirrup
#

in C++23 you could do { auto(point.x) } -> std::same_as<NumberType>;

pastel vale
#

well no, not here actually... hmm...

fickle stirrup
#

instead of having a helper concept

pastel vale
# drowsy vale what did you try

various variations of:

{ point.x } -> std::same_as<std::remove_cvref<NumberType>>;
{ point.y } -> std::same_as<std::remove_cvref<NumberType>>;
drowsy vale
#

ah but that's removing references from NumberType

#

hmm

pastel vale
#

I'll be honest, I have only a vague understand of the syntax here. I'm still learning 😛

drowsy vale
fickle stirrup
#

so the result is a prvalue and qualifiers are removed

drowsy vale
#

oh!

fickle stirrup
drowsy vale
#

i like this "pattern"

fickle stirrup
#

before C++23 you could of course do requires std::same_as<std::remove_cvref_t<decltype(point.x)>,std::remove_cvref_t<NumberType>>;

drowsy vale
#

yeah

pastel vale
#

so, no way to do this inline? The only way I am seeing is my head is to introduce yet another typename which seems silly. Is there no way to have like a variable in the concept? Something like...

{ point.x } -> returnType;
{ point.y } -> returnType;
requites std::same_as<std::remove_cvref<NumberType>, std::remove_cvref<NumberType>>;
fickle stirrup
#

though at that point you could just omit the remove_cvref's probably

#

since decltype would only deduce a reference type here if the member was a reference

#

{ point.x } gets int& because it's actually doing decltype((point.x)) (big difference)

drowsy vale
#

o

pastel vale
#

I was a bit confused by that syntax when I saw it before it seemed nonsensical. ("ensure the runtype is the same as the return type...) but I guess this is a little different then that. Let me try it.

fickle stirrup
#
requires std::same_as<decltype(point.x),NumberType>;
requires std::same_as<decltype(point.y),NumberType>;```
#

that should be good enough

pastel vale
#

yeah that works, groovy.

drowsy vale
#

where SameAsAll concept?

pastel vale
#

Making sure I understand that, here I am saying "ensure the declared type of point.x is the same as NumberType", yes?

#

decltype always seems like some magic box to me

#

carrying these concepts forward is reasonable, yes?

template<typename BoundsType, typename PointType, typename NumberType>
concept Boundslike = requires(BoundsType bounds) {
    requires std::same_as<decltype(bounds.min),PointType>;
    requires std::same_as<decltype(bounds.max),PointType>;
    requires Pointlike<PointType, NumberType>;
};

// defines a type able to return a Bounds object
template <typename ShapeType, typename BoundsType, typename PointType, typename NumberType>
concept Bounded = requires(ShapeType shape) {
    requires std::same_as<decltype(shape.getBounds()), BoundsType>;
    requires Boundslike<BoundsType, PointType, NumberType>;
};

But I don't need to pull the arthematic and Pointlike concepts forward, yes? The underlying concepts should check them.

wicked iceBOT
#

@pastel vale Has your question been resolved? If so, type !solved :)

pastel vale
#

!solved