N3919 - Concepts Lite - Is the syntax redundant

543 views
Skip to first unread message

Vicente J. Botet Escriba

unread,
Oct 27, 2013, 6:31:12 AM10/27/13
to conc...@isocpp.org
Hi,

if a concept is always boolean function, isn't bool redundant?

template<typename T>
concept bool Readable() {
  return requires (T i) {
    typename Value_type<T>;
    {*i} -> const Value_type<T>&;
  };
}

versus

template<typename T>
concept Readable() {
  return requires (T i) {
    typename Value_type<T>;
    {*i} -> const Value_type<T>&;
  };
}

Alternatively we could see it as a variable template

template <typename T>
concept Readable = 
  requires (T i) {
    typename Value_type<T>;
    {*i} -> const Value_type<T>&;
  };

This has the advantage of don't needing to use the call syntax on the require clause

template<Integral T>
requires Unsigned<T>()
T binary_gcd(T a, T b);

versus

template<Integral T>
requires Unsigned<T>
T binary_gcd(T a, T b);

BTW, why the requires expression doesn't needs () in

template<typename T>
concept bool Input_range() {
  return requires(T range) {
    typename Iterator_type<T>;
    requires Input_iterator<T>;
  };
}

As a concept is only applicable to a template we could remove this redundancy
 
concept Readable<typename T> = 
  requires (T i) {
    typename Value_type<T>;
    {*i} -> const Value_type<T>&;
   };


I find that the preceding syntax has less noise than

template<typename T>
concept bool Readable() {
  return requires (T i) {
    typename Value_type<T>;
    {*i} -> const Value_type<T>&;
  };
}

We have removed 3 keywords template, bool and return and replaces '{' '}' by '='

Is this noise absolutely necessary?

Best,
Vicente

More examples from N3919
==========

template<typename T>
concept bool Deref() {
  return requires(T p) {
    {*p} -> T::reference;
  }
}

versus

concept Deref<typename T> = requires(T p)
{
  {*p} -> T::reference;
};

============

template<typename I>
  concept bool Iterator() { ... }
template<typename T>
  concept bool Range() {
    return requires(T x) {
      {begin(x)} -> Iterator; // Iterator
    }
  }

versus

concept Iterator<typename I> = ...;
concept Range <typename T> = requires(T x)
{
  {begin(x)} -> Iterator; // Iterator
};

=========

template<typename T>
concept bool Input_range() {
  return requires(T range) {
    typename Iterator_type<T>;
    requires Input_iterator<T>;
  };
}

versus

concept Input_range <typename T> = requires(T range) {
  typename Iterator_type<T>;
} &&  requires Input_iterator<T>;


==========

template<typename T>
concept bool Integral() { return is_integral<T>::value; }

versus

concept Integral <typename T> = is_integral<T>::value;

==========

template<Integral T>
requires Unsigned<T>()
T binary_gcd(T a, T b);

versus

template<Integral T>
requires Unsigned<T>
T binary_gcd(T a, T b);

versus

template<Integral T>
T binary_gcd(T a, T b) requires Unsigned<T>;


Zhihao Yuan

unread,
Oct 27, 2013, 8:58:45 AM10/27/13
to conc...@isocpp.org

There's an issue with this syntax: can concept definition itself be specialized?  If so, then I don't see how this syntax support specialization.  Function template can do full specialization at least, and constexpr variable template can do partial…

--
Zhihao

--
You received this message because you are subscribed to the Google Groups "SG8 - Concepts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to concepts+u...@isocpp.org.
To post to this group, send email to conc...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/concepts/.

Ville Voutilainen

unread,
Oct 27, 2013, 9:18:25 AM10/27/13
to conc...@isocpp.org
On 27 October 2013 14:58, Zhihao Yuan <z...@miator.net> wrote:

There's an issue with this syntax: can concept definition itself be specialized?  If so, then I don't see how this syntax support specialization.  Function template can do full specialization at least, and constexpr variable template can do partial…



The plan is that concepts cannot be specialized. However, currently it's possible to use
constexpr bool functions as constraints, and those _can_ be specialized.
 

Gabriel Dos Reis

unread,
Oct 27, 2013, 9:31:32 AM10/27/13
to conc...@isocpp.org
Zhihao Yuan <z...@miator.net> writes:

| There's an issue with this syntax: can concept definition itself be
| specialized? 

Not in the current design of concepts lite.

| If so, then I don't see how this syntax support specialization. 
| Function template can do full specialization at least, and constexpr variable
| template can do partial…

-- Gaby

Gabriel Dos Reis

unread,
Oct 27, 2013, 9:32:40 AM10/27/13
to conc...@isocpp.org
Ville Voutilainen <ville.vo...@gmail.com> writes:

| On 27 October 2013 14:58, Zhihao Yuan <z...@miator.net> wrote:
|
|
| There's an issue with this syntax: can concept definition itself be
| specialized?  If so, then I don't see how this syntax support
| specialization.  Function template can do full specialization at least, and
| constexpr variable template can do partial…
|
|
|
|
| The plan is that concepts cannot be specialized.

Right.

| However, currently it's possible to use
| constexpr bool functions as constraints, and those _can_ be specialized.

Fill that under 'implementation details of current concept lites' :-)

-- Gaby

Ville Voutilainen

unread,
Oct 27, 2013, 9:40:08 AM10/27/13
to conc...@isocpp.org
On 27 October 2013 15:32, Gabriel Dos Reis <g...@axiomatics.org> wrote:

| However, currently it's possible to use
| constexpr bool functions as constraints, and those _can_ be specialized.

Fill that under 'implementation details of current concept lites' :-)



I have thought since the very first concepts lite proposal I saw that it would
be fabulous if regular constexpr bool functions work as constraints. For those
who want it, defining concepts with the concept keyword allows an implementation
to do very specific checking, but I'd find it unfortunate if constexpr bool functions
cannot be used for the same thing. I find it practically very pleasant that concepts
lite integrates very well to existing language facilities with very little adaptation
or rewriting.

Zhihao Yuan

unread,
Oct 27, 2013, 9:45:04 AM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 9:40 AM, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> I have thought since the very first concepts lite proposal I saw that it
> would
> be fabulous if regular constexpr bool functions work as constraints.

Ville, have you really tried to define a constexpr bool function
as a concept/constrain, but still accept a function parameter
to do a different thing? I just don't see how a function instead
of a meta function can involve.

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://4bsd.biz/

Ville Voutilainen

unread,
Oct 27, 2013, 9:49:44 AM10/27/13
to conc...@isocpp.org
On 27 October 2013 15:45, Zhihao Yuan <z...@miator.net> wrote:
On Sun, Oct 27, 2013 at 9:40 AM, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> I have thought since the very first concepts lite proposal I saw that it
> would
> be fabulous if regular constexpr bool functions work as constraints.

Ville, have you really tried to define a constexpr bool function
as a concept/constrain, but still accept a function parameter
to do a different thing?  I just don't see how a function instead

Yes. Such as, as a simple, completely artificial and concocted test,

template <class T> constexpr bool calculate(T a, T b)
{
  return a < b;
}

template <> constexpr bool calculate<double>(double a, double b)
{
  return a > b;
}

template <class T>
requires calculate(T(3),T(4))
  void ff()
{
  std::cout << "yes, it works" << std::endl;
}

template <class T>
requires calculate(T(6),T(2))
  void ff()
{
  std::cout << "this one works for double" << std::endl;
}

 
of a meta function can involve.



Feel free to try it out, the branch implementation is available for such
experimentation.

Zhihao Yuan

unread,
Oct 27, 2013, 9:53:24 AM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 9:49 AM, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
>> Ville, have you really tried to define a constexpr bool function
>> as a concept/constrain, but still accept a function parameter
>> to do a different thing? I just don't see how a function instead
> template <class T>
> requires calculate(T(3),T(4))
> void ff()
> {
> std::cout << "yes, it works" << std::endl;
> }
>
> template <class T>
> requires calculate(T(6),T(2))
> void ff()
> {
> std::cout << "this one works for double" << std::endl;
> }

Cool. But, as you can see, this is a constrain, not a concept!
Constraint can be constant expression.

Zhihao Yuan

unread,
Oct 27, 2013, 9:55:24 AM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 9:53 AM, Zhihao Yuan <z...@miator.net> wrote:
> Cool. But, as you can see, this is a constrain, not a concept!
> Constraint can be constant expression.

Any constant expression.

When we are saying "concept" we mean the thing can be use as:

template <Here T>
void f(T t);

Where "Here" is a concept.

Gabriel Dos Reis

unread,
Oct 27, 2013, 9:58:07 AM10/27/13
to conc...@isocpp.org
There is a difference between having "regular constexpr function"
usable in a constraint formulation and allowing concepts to be specialized.
The former does not require the latter, and the latter does not require
the former.

In the current specification of 'concepts lite', we only check uses of
templates on "ground types" or "ground values", e.g. when there is no
template parameter involved in the condition to evaluate. From that
perspective, we are "just" reusing the existing template instantiation
machinery but at a slightly "upper" level. That probably covers more
than half of the situations that people (end users) care about today.
Which is part of the reasons 'concepts lite' are so valuable.

If and when we want to check templates where the actual constraints
involve template parameters (e.g. template definitions), then not being
able to deduce the validity of a generic condition adds a source of
distinct difficulty, if not impossibility, to an already challending task.

-- Gaby

Ville Voutilainen

unread,
Oct 27, 2013, 10:09:36 AM10/27/13
to conc...@isocpp.org
On 27 October 2013 15:58, Gabriel Dos Reis <g...@axiomatics.org> wrote:


There is a difference between having "regular constexpr function"
usable in a constraint formulation and allowing concepts to be specialized.
The former does not require the latter, and the latter  does not require
the former.

Sure. I have no beef with not allowing a concept to be specialized.
 

In the current specification of 'concepts lite', we only check uses of
templates on "ground types" or "ground values", e.g. when there is no
template parameter involved in the condition to evaluate.  From that

I must misunderstand what you're saying here, because the template
parameter of a constrained template seems to me to be used for
the evaluation of the constraint, whether it's a concept or a constrant
expression. It doesn't do lookup/instantiation of explicit concept specializations,
though.
 
perspective, we are "just" reusing the existing template instantiation
machinery but at a slightly "upper" level.  That probably covers more
than half of the situations that people (end users) care about today.
Which is part of the reasons 'concepts lite' are so valuable.

Sure, it's not reinventing very many wheels. That's one of the reasons I
like being able to use constexpr functions in constraints.
 

If and when we want to check templates where the actual constraints
involve template parameters (e.g. template definitions), then not being
able to deduce the validity of a generic condition adds a source of
distinct difficulty, if not impossibility, to an already challending task.



Yep. I can imagine concept specializations making the task quite complex,
and as I said, I have no beef with banning such specializations.

Bjarne Stroustrup

unread,
Oct 27, 2013, 10:17:27 AM10/27/13
to conc...@isocpp.org
On 10/27/2013 5:31 AM, Vicente J. Botet Escriba wrote:
Hi,

if a concept is always boolean function, isn't bool redundant?

Yes. And of course we knew that and has mentioned it repeatedly. We did not want to introduce yet another syntactic pattern. Over the years, the fact that constructors, destructors, and conversion operators have separate carefully minimized syntaxes have cause unanticipated specification problems and user confusion. We don't want to repeat that mistake by minimizing the concept notation (in the obvious ways). Concepts are functions (predicates), so let them look like functions.


Zhihao Yuan

unread,
Oct 27, 2013, 10:24:02 AM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 9:40 AM, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> For
> those
> who want it, defining concepts with the concept keyword allows an
> implementation
> to do very specific checking, but I'd find it unfortunate if constexpr bool
> functions
> cannot be used for the same thing.

OK, I see what do you mean. You mean, although concept
and constrain are different things, but if we regard concept
as a constrain on type, a way to define constrain, like
function template, had better to able to define concept as
well.

The fact is, now we plan to enable constexpr variable template
being used as concept as well. This will raise a question:
which is *the* way to define concept? Where "*the* way" here
means "the standard library way". If we use some form in
standard library, then it will be the official way. If we choose
function template here, it practically kills variable template,
because user will expect a concept can also be used in
constrain in a form of This<T>(); if we choose variable template,
it also kills function template because... You see, there is only
one syntax of concept can practically being used.

Then here I regard constexpr variable template is the best
candidate. The syntax of definition is simpler, the syntax of
use is simpler. And for constrains only deal with types,
like SameType, variable template also works well. Your
use case of using constexpr function as constrain just
work as-is. I don't see a problem.

Gabriel Dos Reis

unread,
Oct 27, 2013, 10:55:20 AM10/27/13
to conc...@isocpp.org
Ville Voutilainen <ville.vo...@gmail.com> writes:

| On 27 October 2013 15:58, Gabriel Dos Reis <g...@axiomatics.org> wrote:
|
|
|
| There is a difference between having "regular constexpr function"
| usable in a constraint formulation and allowing concepts to be specialized.
| The former does not require the latter, and the latter  does not require
| the former.
|
|
| Sure. I have no beef with not allowing a concept to be specialized.
|  
|
|
| In the current specification of 'concepts lite', we only check uses of
| templates on "ground types" or "ground values", e.g. when there is no
| template parameter involved in the condition to evaluate.  From that
|
|
| I must misunderstand what you're saying here, because the template
| parameter of a constrained template seems to me to be used for
| the evaluation of the constraint, whether it's a concept or a constrant
| expression. It doesn't do lookup/instantiation of explicit concept
| specializations,
| though.

We don't evaluate the condition before values are provided for the
template parameters. With 'concepts lite', those values have to be
ground, e.g. 'int', 'vector<string>', '42, et'c. Those values are not
template parameters themselves, or do not involve template parameters.

|  
|
| perspective, we are "just" reusing the existing template instantiation
| machinery but at a slightly "upper" level.  That probably covers more
| than half of the situations that people (end users) care about today.
| Which is part of the reasons 'concepts lite' are so valuable.
|
|
| Sure, it's not reinventing very many wheels. That's one of the reasons I
| like being able to use constexpr functions in constraints.
|  
|
|
| If and when we want to check templates where the actual constraints
| involve template parameters (e.g. template definitions), then not being
| able to deduce the validity of a generic condition adds a source of
| distinct difficulty, if not impossibility, to an already challending task.
|
|
|
|
| Yep. I can imagine concept specializations making the task quite complex,
| and as I said, I have no beef with banning such specializations.


-- Gaby

Ville Voutilainen

unread,
Oct 27, 2013, 12:04:23 PM10/27/13
to conc...@isocpp.org
On 27 October 2013 16:55, Gabriel Dos Reis <g...@axiomatics.org> wrote:
|
|     In the current specification of 'concepts lite', we only check uses of
|     templates on "ground types" or "ground values", e.g. when there is no
|     template parameter involved in the condition to evaluate.  From that
|
|
| I must misunderstand what you're saying here, because the template
| parameter of a constrained template seems to me to be used for
| the evaluation of the constraint, whether it's a concept or a constrant
| expression. It doesn't do lookup/instantiation of explicit concept
| specializations,
| though.

We don't evaluate the condition before values are provided for the
template parameters.  With 'concepts lite', those values have to be
ground, e.g. 'int', 'vector<string>', '42, et'c.  Those values are not
template parameters themselves, or do not involve template parameters.



Ah, sure. I didn't even imagine reaching as far as having template parameters
at the condition evaluation time, regardless of whether the constraint
happens to be a template with possible specializations.

Gabriel Dos Reis

unread,
Oct 27, 2013, 12:57:08 PM10/27/13
to conc...@isocpp.org
Well, this is what it means to check template definitions :-)

-- Gaby

Ville Voutilainen

unread,
Oct 27, 2013, 1:04:22 PM10/27/13
to conc...@isocpp.org
On 27 October 2013 18:57, Gabriel Dos Reis <g...@axiomatics.org> wrote:
|
|     We don't evaluate the condition before values are provided for the
|     template parameters.  With 'concepts lite', those values have to be
|     ground, e.g. 'int', 'vector<string>', '42, et'c.  Those values are not
|     template parameters themselves, or do not involve template parameters.
|
|
| Ah, sure. I didn't even imagine reaching as far as having template parameters
| at the condition evaluation time, regardless of whether the constraint
| happens to be a template with possible specializations.

Well, this is what it means to check template definitions :-)



I never looked at it that way, but sure, that makes sense. It's been a while since
C++0x concepts.. ..and there's been very little concrete talk about what it actually
involves to check a definition as an evolutionary step from concepts lite.

Perhaps this means that in order to check a definition, we need to have an actual
concept, not just any predicate like a constexpr function or a constexpr function
template, then? And we likely need some way of saying that definition checking
is desired, I still don't think it should just happen automatically.

Gabriel Dos Reis

unread,
Oct 27, 2013, 1:13:14 PM10/27/13
to conc...@isocpp.org
Ville Voutilainen <ville.vo...@gmail.com> writes:

| On 27 October 2013 18:57, Gabriel Dos Reis <g...@axiomatics.org> wrote:
|
| |
| |     We don't evaluate the condition before values are provided for the
| |     template parameters.  With 'concepts lite', those values have to be
| |     ground, e.g. 'int', 'vector<string>', '42, et'c.  Those values are
| not
| |     template parameters themselves, or do not involve template
| parameters.
| |
| |
| | Ah, sure. I didn't even imagine reaching as far as having template
| parameters
| | at the condition evaluation time, regardless of whether the constraint
| | happens to be a template with possible specializations.
|
| Well, this is what it means to check template definitions :-)
|
|
|
|
| I never looked at it that way, but sure, that makes sense. It's been a while
| since
| C++0x concepts.. ..and there's been very little concrete talk about what it
| actually
| involves to check a definition as an evolutionary step from concepts lite.
|
| Perhaps this means that in order to check a definition, we need to have an
| actual
| concept, not just any predicate like a constexpr function or a constexpr
| function
| template, then?

Correct.

Note that 'constraints' can specify syntactic requirements though.

| And we likely need some way of saying that definition checking
| is desired, I still don't think it should just happen automatically.

-- Gaby

Vicente J. Botet Escriba

unread,
Oct 27, 2013, 3:03:46 PM10/27/13
to conc...@isocpp.org
Le 27/10/13 13:58, Zhihao Yuan a �crit :
>
> There's an issue with this syntax: can concept definition itself be
> specialized? If so, then I don't see how this syntax support
> specialization. Function template can do full specialization at
> least, and constexpr variable template can do partial�
>
I don't see what you mean by concept specialization. Could you give an
example?
Vicente

Zhihao Yuan

unread,
Oct 27, 2013, 3:26:13 PM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 3:03 PM, Vicente J. Botet Escriba
<vicent...@wanadoo.fr> wrote:
> I don't see what you mean by concept specialization. Could you give an
> example?

This is a wild idea,


template<typename T>
concept bool Integral() { return is_integral<T>::value; }

// I don't mean this, just an example
template<>
concept bool Integral<BigInt>() { return true; }

This one is not supported yet (only the main template will be
looked at as a concept, but the whole specialization family
can be used as a constrain, IIUC).

Concept defines something general, and if it can be specialized,
that's like to define exceptions of such a general definition.

We vaguely know how it works, but I don't know how it can be
useful, and have no idea whether we should add it.

But Ville, if you want to make more constrains "just works" as
concepts, this feature is kind of essential, otherwise, you know,
user astonishment.

Bjarne Stroustrup

unread,
Oct 27, 2013, 3:40:13 PM10/27/13
to conc...@isocpp.org
On 10/27/2013 2:26 PM, Zhihao Yuan wrote:
> On Sun, Oct 27, 2013 at 3:03 PM, Vicente J. Botet Escriba
> <vicent...@wanadoo.fr> wrote:
>> I don't see what you mean by concept specialization. Could you give an
>> example?
> This is a wild idea,
>
>
> template<typename T>
> concept bool Integral() { return is_integral<T>::value; }
>
> // I don't mean this, just an example
> template<>
> concept bool Integral<BigInt>() { return true; }

but why? Why would you want to do that? And why not specialize is_integral?

Zhihao Yuan

unread,
Oct 27, 2013, 3:48:43 PM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 3:40 PM, Bjarne Stroustrup <b...@cs.tamu.edu> wrote:
>> // I don't mean this, just an example
>> template<>
>> concept bool Integral<BigInt>() { return true; }
>
> but why? Why would you want to do that? And why not specialize is_integral?

.:T_T:. I said, "I don't mean this" and "I don't know how it can be
useful"... To specialize a concept is literally breaking a concept,
literally... That's my understanding.

Zhihao Yuan

unread,
Oct 27, 2013, 4:20:29 PM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 6:31 AM, Vicente J. Botet Escriba
<vicent...@wanadoo.fr> wrote:
> template<typename T>
> concept bool Input_range() {
> return requires(T range) {
> typename Iterator_type<T>;
> requires Input_iterator<T>;
> };
> }
>
> versus
>
> concept Input_range <typename T> = requires(T range) {
> typename Iterator_type<T>;
> } && requires Input_iterator<T>;

We already know that concept is unray type predicate, and it seems
that we have no interests, no plan to support concept specialization,
then what we leave the `typename` keyword here for?

concept Input_range<T> = requires(T range) {
typename Iterator_type<T>;
} && requires Input_iterator<T>;

Looks more clear to me, like a term-rewriting.

Ville Voutilainen

unread,
Oct 27, 2013, 5:13:27 PM10/27/13
to conc...@isocpp.org
On 27 October 2013 22:20, Zhihao Yuan <z...@miator.net> wrote:

We already know that concept is unray type predicate, and it seems
that we have no interests, no plan to support concept specialization,
then what we leave the `typename` keyword here for?

  concept Input_range<T> = requires(T range) {
    typename Iterator_type<T>;
  } &&  requires Input_iterator<T>;

Looks more clear to me, like a term-rewriting.



Why? Because we don't want concepts to have a wildly different syntax
compared to existing facilities. That eases the implementation, and
arguably eases the task for humans recognizing the syntactical patterns in the code,
without having to switch gears when writing constrained code and concepts
compared to writing 'regular' code. It seems that whenever we introduce
a new facility, people love going wild over all the possibilities of reinventing
new syntaxes, conveniently forgetting that the old syntaxes are still there,
so adding completely different syntaxes for the new things doesn't necessarily
make the language any easier to learn, teach and use. The same thing almost
happened with polymorphic lambdas, but we have thus far remained conservatively
careful about those.

Zhihao Yuan

unread,
Oct 27, 2013, 5:37:18 PM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 5:13 PM, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
>> concept Input_range<T> = requires(T range) {
>> typename Iterator_type<T>;
>> } && requires Input_iterator<T>;
>>
>> Looks more clear to me, like a term-rewriting.
>
> Why? Because we don't want concepts to have a wildly different syntax
> compared to existing facilities.

This thread starts with "a wildly different" syntax, so it appears that
some people want.

I'm just brain storming this thought. I'm neutral to +1 about this syntax.

> That eases the implementation, and
> arguably eases the task for humans recognizing the syntactical patterns in
> the code,
> without having to switch gears when writing constrained code and concepts
> compared to writing 'regular' code.

Andrew says (to me, on cppnow) Concepts should be defined in a
centralized place per project. If that's true, then you may not have
a chance to "switch gears" between looking at constrain definition
and concepts definition.

> so adding completely different syntaxes for the new things doesn't
> necessarily
> make the language any easier to learn, teach and use.

While subseting an existing syntax may make the language
harder to learn, teach, and use. When I say "subseting" I mean:

N3701 7.1.7:

Concept definitions have the following restrictions:

- The template must be unconstrained.
- The result type must be bool.
- The declaration may have no function parameters.
- The declaration must be defined.
- The function shall not be recursive.

After constexpr function is being relaxed, you will need to
exclude more rules here, pretty much by reverting N3652.

And, now we know, the template must not be specialized.

So, why subseting? Subseting usually means that the old
feature is not quite the thing you want; what you want is a
different thing. I prefer to leave different thing different.

Ville Voutilainen

unread,
Oct 27, 2013, 6:03:40 PM10/27/13
to conc...@isocpp.org
On 27 October 2013 23:37, Zhihao Yuan <z...@miator.net> wrote:
> Why? Because we don't want concepts to have a wildly different syntax
> compared to existing facilities.

This thread starts with "a wildly different" syntax, so it appears that
some people want.

Yes, I use the term "we" overly liberally, in most of my writings it means
"people Ville deems sane or thinks he can convince to agree with him,
thus converting them to sane people".

 
> That eases the implementation, and
> arguably eases the task for humans recognizing the syntactical patterns in
> the code,
> without having to switch gears when writing constrained code and concepts
> compared to writing 'regular' code.

Andrew says (to me, on cppnow) Concepts should be defined in a
centralized place per project.  If that's true, then you may not have
a chance to "switch gears" between looking at constrain definition
and concepts definition.

I'm not talking about concepts vs. constraints. I'm talking about unconstrained
existing code and constrained new code. I prefer having a minimized difference
between them.

Bjarne Stroustrup

unread,
Oct 27, 2013, 6:13:21 PM10/27/13
to conc...@isocpp.org
On 10/27/2013 5:03 PM, Ville Voutilainen wrote:
>
>
>
>
>
> I'm not talking about concepts vs. constraints. I'm talking about
> unconstrained
> existing code and constrained new code. I prefer having a minimized
> difference
> between them.
That's important: there is a large body of code where (say)
Forward_iterator and typename will be interchangeable when moving back
and forth between C+11 and C++14.

Zhihao Yuan

unread,
Oct 27, 2013, 6:21:40 PM10/27/13
to conc...@isocpp.org
On Sun, Oct 27, 2013 at 6:03 PM, Ville Voutilainen
<ville.vo...@gmail.com> wrote:
> Yes, I use the term "we" overly liberally, in most of my writings it means
> "people Ville deems sane or thinks he can convince to agree with him,
> thus converting them to sane people".

lol

> I'm not talking about concepts vs. constraints. I'm talking about
> unconstrained
> existing code and constrained new code. I prefer having a minimized
> difference
> between them.

Then what you may want to care about is what a constrained
declaration looks like (like Bjarne said, concept-name in place of
`typename`). Concept definition is new, as well as
_requires-expression_. So I'm fine if concept definition looks
"wildly different" (since _requires-expression_ is wild enough :)
and I'm also fine if it's based on constexpr variable template,
since you need to subset nearly nothing.

Ville Voutilainen

unread,
Oct 27, 2013, 6:53:18 PM10/27/13
to conc...@isocpp.org
On 28 October 2013 00:21, Zhihao Yuan <z...@miator.net> wrote:

> I'm not talking about concepts vs. constraints. I'm talking about
> unconstrained
> existing code and constrained new code. I prefer having a minimized
> difference
> between them.

Then what you may want to care about is what a constrained
declaration looks like (like Bjarne said, concept-name in place of
`typename`).  Concept definition is new, as well as

Well, yes,
template <Concept C>
instead of
template <class C>
a very small difference.
 
_requires-expression_.  So I'm fine if concept definition looks
"wildly different" (since _requires-expression_ is wild enough :)

The concept definition is as simple as replacing one 'constexpr'
with 'concept', a very small difference. The requires-expression
is anything but wild, it looks quite similar to a lambda.
Message has been deleted

Bjarne Stroustrup

unread,
Oct 28, 2013, 6:12:11 PM10/28/13
to conc...@isocpp.org
On 10/28/2013 4:00 PM, toma...@gmail.com wrote:

It seems to me that you are (all) trying to make concepts values/objects. They are predicates.


While subseting an existing syntax may make the language
harder to learn, teach, and use.  When I say "subseting" I mean:

N3701 7.1.7:

  Concept definitions have the following restrictions:

  - The template must be unconstrained.
  - The result type must be bool.
  - The declaration may have no function parameters.
  - The declaration must be defined.
  - The function shall not be recursive.

After constexpr function is being relaxed, you will need to
exclude more rules here, pretty much by reverting N3652.

I think with this restriction provided it is better and less suprising
to model the concepts (not constraints) as a template variable
in a form:
template<typename T>
concept bool C<T> = requires ...;


Using the variable syntax already imposes the two restrictions that
are not so intuitive for the constexpr functions used as concepts:
no parameters allowed and allowance of only one statement that is return,
which was removed from the lastest standard for constexpr functions.

So I your are not planning to allow concepts (not constraint) with
parameters in further revisions, I think it would be better to allow
only variable syntax for concepts, because the restrictions of
concepts that are imposed for the constexpr functions will no longer
 be needed, expect the one about specializations.

Also I think it will make the possible future syntax for any "full" concepts
more coherent as we will have:
template<typename T>
concept bool C<T> { requires ... };
And eventually:
template<typename T>
concept class C<T> { requires ... };


Vicente J. Botet Escriba

unread,
Oct 28, 2013, 6:25:46 PM10/28/13
to conc...@isocpp.org
Le 28/10/13 23:12, Bjarne Stroustrup a écrit :
On 10/28/2013 4:00 PM, toma...@gmail.com wrote:

It seems to me that you are (all) trying to make concepts values/objects. They are predicates.

A bool constexpr template variable having types as template parameters is a type-predicate.
No need to add parenthesis.
The parameter are the types. The result bool.

Vicente

Richard Smith

unread,
Oct 28, 2013, 10:11:02 PM10/28/13
to conc...@isocpp.org
Neither functions or variables seem like the right model here. Both models give you an entity with an address and linkage, for instance, which seems gratuitous. It seems to me that a concept is some hybrid of:
 1) An alias for a predicate, represented as an expression. [It's an alias in the sense of an alias-declaration: the alias is notionally substituted prior to instantiation, since an implementation is expected to decompose it into constituent && and || operands for template partial ordering.]
 2) A type name, naming some unknown type that matches the predicate.

This sounds nothing like either a function or a variable to me. I support the original suggestion on this thread of a syntax like:

  concept Foo<typename T> = predicate;

and dropping any notion of a concept being a variable or a function.


[FWIW, the decompose-into-&&-and-||-operands part sounds like a problematic idea to me. You cannot know, when seeing the proposition

  is_foo<X>::type && is_bar<X>::type

whether "is_foo<X>() && is_bar<X>()" is an atomic proposition, because (for instance) is_foo<X>() and is_bar<X>() might return some non-bool type Y with an overloaded "bool operator&&(Y, Y);".]

Zhihao Yuan

unread,
Oct 28, 2013, 10:32:20 PM10/28/13
to conc...@isocpp.org
On Mon, Oct 28, 2013 at 10:11 PM, Richard Smith <richar...@google.com> wrote:
> Neither functions or variables seem like the right model here. Both models
> give you an entity with an address and linkage, for instance, which seems
> gratuitous. It seems to me that a concept is some hybrid of:
> 1) An alias for a predicate, represented as an expression. [It's an alias
> in the sense of an alias-declaration: the alias is notionally substituted
> prior to instantiation, since an implementation is expected to decompose it
> into constituent && and || operands for template partial ordering.]
> 2) A type name, naming some unknown type that matches the predicate.
>
> This sounds nothing like either a function or a variable to me. I support
> the original suggestion on this thread of a syntax like:
>
> concept Foo<typename T> = predicate;
>
> and dropping any notion of a concept being a variable or a function.

As I said, I +1; plus a little bit curious why `typename` is not
dropped altogether, when there is not `template`.

> [FWIW, the decompose-into-&&-and-||-operands part sounds like a problematic
> idea to me. You cannot know, when seeing the proposition
>
> is_foo<X>::type && is_bar<X>::type
>
> whether "is_foo<X>() && is_bar<X>()" is an atomic proposition, because (for
> instance) is_foo<X>() and is_bar<X>() might return some non-bool type Y with
> an overloaded "bool operator&&(Y, Y);".]

&& and || are only being interpreted as tokens without further
investigation here, so I suggested Andrew to use a different
pair of tokens, like, giving `and` and `or` special meaning inside
a concept definition -- you can't use `&&` and `||`. Or maybe we
can try new keywords.

Botond Ballo

unread,
Oct 28, 2013, 10:45:03 PM10/28/13