Mathieu Van Nevel Mathieu Van Nevel - 10 days ago 5
C++ Question

C++ concepts: Some signatures function conversion

Unfortunately, the only tutorial that I have found about

concepts
was the concept lite tutorial (and it was really basic). And even with the technical specification, there is some signatures function that I don't know how translate into concepts (maybe just because my English is bad and I can't read the technical specification really well).

So there is a list of signatures function I still don't know how to "translate":

CFoo --> class CFoo {};


  • void Foo1() const;

  • CFoo& Foo2();

  • void Foo3(CFoo&);

  • {static, friend, ... } void Foo4();

  • template < typename ... Args >
    void Foo5(Args && ... args);



I want to have some kind of interface for a class with these functions.
Don't even know if it's possible at this point. Foo2 and Foo3 seems to be the same problem.




Honestly I really want to know Foo2 and Foo5.

I tried somethings, for the Foo2 but I don't have any idea about Foo5:

class Handle {};

template < typename Object >
concept bool C_Object =
requires(Handle handle) {
{get(handle)} -> Object&
};

template < C_Object Object >
class Foo {

Object obj;
};

int main() {

Foo<int> test;
return 0;
}


I know this won't compile because Foo don't have a get menber, but these are not the right errors:

Test1.cpp:6:16: error: there are no arguments to ‘get’ that depend on a template parameter, so a declaration of ‘get’ must be available [-fpermissive]
{get(handle)} -> Object&
^
Test1.cpp:6:16: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
Test1.cpp: In function ‘int main()’:
Test1.cpp:18:10: error: template constraint failure
Foo<int> test;
^
Test1.cpp:18:10: note: constraints not satisfied
Test1.cpp:4:14: note: within ‘template<class Object> concept const bool C_Object<Object> [with Object = int]’
concept bool C_Object =
^~~~~~~~
Test1.cpp:4:14: note: with ‘Handle handle’
Test1.cpp:4:14: note: the required expression ‘get(handle)’ would be ill-formed


If someone can point me out some resources or, why not, a solution. It will be great.

Have a great day

Answer

I know this won't compile because Foo don't have a get menber […]

Concepts deal with normal expressions. In particular, the scope of requires expressions is normal scope, not class scope. This may be more apparent with this concept:

template<typename Lhs, typename Rhs>
concept bool Addable = requires(Lhs lhs, Rhs rhs) {
    lhs + rhs;
};

Addable<int, long> is fulfilled because given int lhs; long rhs; then lhs + rhs is a valid expression. We're using the built-in addition operator on two (pretend) variables we explicitly introduced in the parameter list, not calling a member operator+ on an implicit *this.

Concepts are about interfaces in the wider sense (as in 'API'), not in a narrower OOP sense. You can think of Addable as a relation on pairs of types. That Addable<int, long> holds doesn't mean int on its own has a special relationship with Addable. It is true that Addable can be used as e.g.

template<Addable<long> Var>
struct client {
    Var var;
};

and then client<int> comes with an Addable<int, long> constraint, but this shortcut is syntactical in nature. It's a helpful way of cutting down boilerplate, namely sparing us from writing template<typename Var> requires Addable<Var, long>.

With that in mind, here are some expressions that may come close to checking the member signatures you mentioned, plus the Handle scenario:

template<typename Obj>
concept bool Object = requires(Obj obj, Obj const cobj, Handle handle) {
    cobj.Foo1();
    { obj.Foo2() } -> Obj&;
    obj.Foo3(obj);
    // static
    Obj::Foo4();
    // non-member, possibly friend
    Foo4(obj);

    { obj.get(handle) } -> Obj&;
};

(I elided the Foo5 scenario because it's worth its own question, here is a lead.)