Definition requiring a limited member function

Note: all that follows uses TS Concepts implementation in GCC 6.1

Say I have a Surface concept as shown below:

 template <typename T> concept bool Surface() { return requires(T& t, point2f p, float radius) { { t.move_to(p) }; { t.line_to(p) }; { t.arc(p, radius) }; // etc... }; } 

Now I want to define another Drawable concept that matches any type with a member function:

 template <typename S> requires Surface<S>() void draw(S& surface) const; 

i.e.

 struct triangle { void draw(Surface& surface) const; }; static_assert(Drawable<triangle>(), ""); // Should pass 

That is, Drawable is what has the templated const member draw() function, referencing an lvalue link to what meets the requirements of Surface . This is easy enough to indicate in words, but I can’t decide how to do this in C ++ using Concepts TS. The "obvious" syntax does not work:

 template <typename T> concept bool Drawable() { return requires(const T& t, Surface& surface) { { t.draw(surface) } -> void; }; } 

error: parameter 'auto' is not allowed in this context

Adding a second template parameter allows you to compile the concept, but:

 template <typename T, Surface S> concept bool Drawable() { return requires(const T& t, S& s) { { t.draw(s) }; }; } static_assert(Drawable<triangle>(), ""); 

Error in outputting template argument: could not output template parameter 'S'

now we can only check whether a particular pair of < Drawable , Surface > Drawable concepts, which is not entirely correct. (Type D either has the required member function or not: it does not depend on which Surface we are testing.)

I am sure that it is possible to do what I need, but I can not understand the syntax, and so far there are not many examples online. Does anyone know how to write a definition of a concept that requires a type to have a limited member function?

+5
source share
1 answer

What you are looking for is a compiler way to synthesize the Surface archetype. That is, a private, anonymous type that minimally satisfies the concept of Surface . At least minimally. Concepts TS currently does not currently provide a mechanism for automatic synthesis of archetypes, so we need to do this manually. This is a rather complicated process , since it is very easy to find candidates for archetypes who have more opportunities that the concept defines.

In this case, we can come up with something like:

 namespace archetypes { // don't use this in real code! struct SurfaceModel { // none of the special members SurfaceModel() = delete; SurfaceModel(SurfaceModel const& ) = delete; SurfaceModel(SurfaceModel&& ) = delete; ~SurfaceModel() = delete; void operator=(SurfaceModel const& ) = delete; void operator=(SurfaceModel&& ) = delete; // here the actual concept void move_to(point2f ); void line_to(point2f ); void arc(point2f, float); // etc. }; static_assert(Surface<SurfaceModel>()); } 

And then:

 template <typename T> concept bool Drawable() { return requires(const T& t, archetypes::SurfaceModel& surface) { { t.draw(surface) } -> void; }; } 

These are valid concepts that probably work. Please note that there are many possibilities for further refinement of the SurfaceModel archetype. I have a specific function void move_to(point2f ) , but the concept just requires it to be called with an lvalue of type point2f . There is no requirement that move_to() and line_to() take an argument of type point2f , they can take different things:

 struct SurfaceModel { // ... struct X { X(point2f ); }; struct Y { Y(point2f ); }; void move_to(X ); void line_to(Y ); // ... }; 

This paranoia makes the best archetype and serves to illustrate how complex this problem is.

+2
source

All Articles