Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
423 views
in Technique[技术] by (71.8m points)

c++ - How can unspecified types be used in C++20 'requires' expressions?

I'm trying to write a C++20 concept to express the requirement that a type have a certain method, which takes an argument, but for the purposes of this concept I don't care what the argument type is.

I've tried to write something like:

template <typename T>
concept HasFooMethod = requires(T t, auto x)
{
    { t.Foo(x) } -> std::same_as<void>;
};

however, both gcc and clang reject this, giving an error that 'auto' cannot be used in the parameter list of a requires expression this way.

An alternative would be to put the type of 'x' as a second template parameter:

template <typename T, typename TX>
concept HasFooMethod = requires(T t, TX x)
{
    { t.Foo(x) } -> std::same_as<void>;
};

but then this requires TX to be specified explicitly whenever the concept is used, it cannot be deduced:

struct S { void Foo(int); };
static_assert(HasFooMethod<S>);         // doesn't compile
static_assert(HasFooMethod<S, int>);    // the 'int' must be specified

Is there any way to write a concept that allows Foo to take an argument of unspecified type?

The question Concept definition requiring a constrained template member function is very similar, but not the same: that question asks how to require that a (templated) method can take any type satisfying a given concept, while this question is about requiring that a method takes some particular type, although that type is unspecified. In terms of quantifiers, the other question is asking about (bounded) universal quantification while this one is about existential quantification. The other question's answer also does not apply to my case.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Concepts are not intended to provide the kind of functionality you are looking for. So they don't provide it.

A concept is meant to constrain templates, to specify a set of expressions or statements that a template intends to use (or at least be free to use) in its definition.

Within the template that you are so constraining, if you write the expression t.Foo(x), then you know the type of x. It is either a concrete type, a template parameter, or a name derived from a template parameter. Either way, the type of x is available at the template being constrained.

So if you want to constrain such a template, you use both the type of t and the type of x. Both are available to you at that time, so there is no problem with creating such a constraint. That is, the constraint is not on T as an isolated type; it's on the association between T and X.

Concepts aren't meant to work in a vacuum, devoid of any association with the actual place of usage of the constraint. You shouldn't focus on creating unary concepts so that users can static_assert their classes against them. Concepts aren't meant for testing if a type fulfills them (which is basically what your static_assert is doing); they're meant for constraining the template definition that uses them.

Your constraint needs to be FooCallableWith, not HasFooMethod.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.8k users

...