问题
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.
回答1:
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 allIncrementable
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.
回答2:
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.
来源:https://stackoverflow.com/questions/53576429/something-like-declval-for-concepts