Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Something like `declval` for concepts

When you are working with templates and with decltype you often need an instance of a certain type even though you do not have any the moment. In this case, std::declval<T>() is incredibly useful. This creates an imaginary instance of the type T.

Is there a something similar for concepts? i.e. a function which would create and imaginary type for a concept.

Let me give you an example(a bit contrived but should serve the purpose):

Let's define a concept Incrementable

template <typename T>
concept Incrementable = requires(T t){
   { ++t } -> T;                       
};

Now I would like to have a concept which tests if an object has the operator operator() which can accept Incrementable. In my imaginary syntax I would write something like this:

template <typename F, typename T = declval<Incrementable>>
concept OperatesOnIncrementable = requires(F f, T t){
   { f(t) } -> T;
} 

There the declval in typename T = declval<Incrementable> would create an imaginary type T which is not really a concrete type but for all intents and purposes behaves like a type which satisfies Incrementable.

Is there a mechanism in the upcoming standard to allow for this? I would find this incredibly useful.


Edit: Some time ago I have asked a similar question if this can be done with boost::hana.


Edit: Why is this useful? For example if you want to write a function which composes two functions

template <typename F, typename G>
auto compose(F f, G g) {
  return [f, g](Incrementable auto x) { return f(g(x)); };
}

I want to get an error when I try to compose two functions which cannot be composed. Without constraining the types F and G I get error only when I try to call the composed function.

like image 439
tom Avatar asked Dec 08 '22 13:12

tom


2 Answers

There is no such mechanism.

Nor does this appear to be implementable/useful, since there is an unbounded number of Incrementable types, and F could reject a subset selected using an arbitrarily complex metaprogram. Thus, even if you could magically synthesize some unique type, you still have no guarantee that F operates on all Incrementable types.

like image 118
T.C. Avatar answered Dec 29 '22 22:12

T.C.


Is there a something similar for concepts? i.e. a function which would create and imaginary type for a concept.

The term for this is an archetype. Coming up with archetypes would be a very valuable feature, and is critical for doing things like definition checking. From T.C.'s answer:

Thus, even if you could magically synthesize some unique type, you still have no guarantee that F operates on all Incrementable types.

The way to do that would be to synthesize an archetype that as minimally as possible meets the criteria of the concept. As he says, there is no archetype generation in C++20, and is seems impossible given the current incarnation of concepts.


Coming up with the correct archetype is incredibly difficult. For example, for

template <typename T>
concept Incrementable = requires(T t){
   { ++t } -> T;                       
};

It is tempting to write:

struct Incrementable_archetype {
    Incrementable_archetype operator++();
};

But that is not "as minimal as possible" - this type is default constructible and copyable (not requirements that Incrementable imposes), and its operator++ returns exactly T, which is also not the requirement. So a really hardcore archetype would look like:

struct X {
    X() = delete;
    X(X const&) = delete;
    X& operator=(X const&) = delete;

    template <typename T> operator,(T&&) = delete;

    struct Y {
        operator X() &&;
    };
    Y operator++();
};

If your function works for X, then it probably works for all Incrementable types. If your function doesn't work for X, then you probably need to either change the implementation so it does or change the constraints to to allow more functionality.

For more, check out the Boost Concept Check Library which is quite old, but is very interesting to at least read the documentation.

like image 34
Barry Avatar answered Dec 29 '22 20:12

Barry