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
to conc...@isocpp.org

On Monday, October 28, 2013 10:32:20 PM UTC-4, Zhihao Yuan wrote:
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`.

I like this syntax too.

I think the typename is necessary because concepts can constrain non-type and template template parameters as well as type template parameters.

Regards,
Botond

Zhihao Yuan

unread,
Oct 28, 2013, 10:54:18 PM10/28/13
to conc...@isocpp.org
On Mon, Oct 28, 2013 at 10:45 PM, Botond Ballo <botond...@gmail.com> wrote:
> I think the typename is necessary because concepts can constrain non-type
> and template template parameters as well as type template parameters.

Serious?

concept EOF<int N> = N == -1;

template <EOF C>
auto parsing(...) {}

... I can't continue.

concept UnaryMetaFunction<template class <typename>> == true;

This makes a little bit more sense, but... AFAIK concept only
works on types. I don't other people's position.

Botond Ballo

unread,
Oct 28, 2013, 11:00:33 PM10/28/13
to conc...@isocpp.org
On Monday, October 28, 2013 10:54:18 PM UTC-4, Zhihao Yuan wrote:
On Mon, Oct 28, 2013 at 10:45 PM, Botond Ballo <botond...@gmail.com> wrote:
> I think the typename is necessary because concepts can constrain non-type
> and template template parameters as well as type template parameters.

Serious?
 
Yes. See sections 3.4 and 3.5 of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3701.pdf.

Regards,
Botond

Bjarne Stroustrup

unread,
Oct 28, 2013, 11:03:10 PM10/28/13
to conc...@isocpp.org
On 10/28/2013 9:32 PM, Zhihao Yuan wrote:

I just had a great idea! Since you (several of you) have so many ideas
and so many complex objections to "concepts lite," why don't you make an
alternative design. Agree on a syntax and a semantics, implement it, try
it out on a few thousands of lines of code (incl. the C++standard
library), document it, write up tutorial material, write up the design
alternatives, write up some documentation, and try out your ideas on a
few hundred programmers? That way, we don't have to discuss your
individual ideas i isolation without a good understanding of your
underlying ideas.

Please consider:
http://www.stroustrup.com/sle2011-concepts.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3819.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf
as part of your background material and discuss how your design and
implementation improves on the design decisions and principles there.

I really dislike the twitter-style exchanges masquerading as design
discussions. Make a complete design, try it out, and then seriously
compare it to alternatives, such as "concepts lite" and C++0x concepts.

Please do remember that the alternative to a consensus in no concepts in
C++14 (or C++17).

Zhihao Yuan

unread,
Oct 28, 2013, 11:04:22 PM10/28/13
to conc...@isocpp.org
On Mon, Oct 28, 2013 at 11:00 PM, Botond Ballo <botond...@gmail.com> wrote:
>> > I think the typename is necessary because concepts can constrain
>> > non-type
>> > and template template parameters as well as type template parameters.
>>
>> Serious?
>
> Yes. See sections 3.4 and 3.5 of
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3701.pdf.

Ehh, well, thanks.

Zhihao Yuan

unread,
Oct 29, 2013, 1:10:31 AM10/29/13
to conc...@isocpp.org
On Mon, Oct 28, 2013 at 11:03 PM, Bjarne Stroustrup <b...@cs.tamu.edu> wrote:
> I just had a great idea! Since you (several of you) have so many ideas and
> so many complex objections to "concepts lite," why don't you make an
> alternative design. Agree on a syntax and a semantics, implement it, try it
> out on a few thousands of lines of code (incl. the C++standard library),
> document it, write up tutorial material, write up the design alternatives,
> write up some documentation, and try out your ideas on a few hundred
> programmers? That way, we don't have to discuss your individual ideas i
> isolation without a good understanding of your underlying ideas.

I just had a great idea, too!

http://www.boost.org/doc/libs/1_54_0/libs/concept_check/using_concept_check.htm

=== cut === cut ===

So, you see, I'm not like some people who comes from the old
concepts, I'm not attacking "concepts-lite" by saying "why it does
not check definition" or whatever, not even "why operator&& does
not work". Andrew explained how "concept-lite" works, so I
noticed that there are something had better to be exposed to
interface, to end users, so that we don't confuse or astonish them.

I respect and feel grateful about your work on concepts-lite
(although I think I'm not even qualified to say so), and I'm very
happy to see something named concepts already works. But
there is one thing that I don't understand: In concept-lite, concept
definition is a completely different world from the rest of the
program written in C++, what is the point of making it looks like
the existing part of C++ but doing different things? People ask
Andrew why !negation does not work on cppnow, people ask
about C++14 unrestricted constexpr function as concept
definition, people ask about "concept specialization", so on so
forth.

Let me say this again: subsetting an existing syntax may make
the language harder to learn, teach, and use. This is something
fairly straightforward: people see something familiar -> people
think the things of the same category which they are familiar
with, work.

In Chicago, you said "bikesheds usually covers for something
deeper". I'm suggesting nothing deeply different, and I have no
underlying ideas. All I wish is that the spirit of "concept-lite" is
not overshadowed by its syntax. Currently, the syntax is borrowed
from constexpr function template, cutting off the things not suite
for "concept-lite"'s needs, and being interpreted differently. And
those questions are the result: the feature becomes hard to learn,
to teach, and, hope we don't reach this, to use.

I listen to your indoctrination and shut up.

Andrew Sutton

unread,
Oct 29, 2013, 10:57:48 AM10/29/13
to conc...@isocpp.org
> [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

Do you mean ::value? I wouldn't expect this to compile if ::type named a 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);".]

Yes, and the overload could conceivably implement non-Boolean
semantics, which creates a nice hole in the logic.

I think the current wording says that user-defined overloads of
logical operators are not considered when parsing constraints. Or it
should say something to that effect. That's one approach...

Another would be to make the program ill-formed. That seems a bit extreme.

We could also say that a conjunction or disjunction that resolves to a
user-defined overload is an atomic proposition. This approach seems to
have some merit. It bears some thinking about.

Andrew

Gabriel Dos Reis

unread,
Oct 29, 2013, 11:13:13 AM10/29/13
to conc...@isocpp.org
Andrew Sutton <andrew....@gmail.com> writes:

| > [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
|
| Do you mean ::value? I wouldn't expect this to compile if ::type named a 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);".]
|
| Yes, and the overload could conceivably implement non-Boolean
| semantics, which creates a nice hole in the logic.

Hmm, I don't remember we decided that "concept" would return or evaluate
to anything other than a bool, so I am puzzled by this mysterious Y.

I think it is very important that we take in the feedbacks but don't make any
design decision on the fly.

|
| I think the current wording says that user-defined overloads of
| logical operators are not considered when parsing constraints. Or it
| should say something to that effect. That's one approach...
|
| Another would be to make the program ill-formed. That seems a bit extreme.
|
| We could also say that a conjunction or disjunction that resolves to a
| user-defined overload is an atomic proposition. This approach seems to
| have some merit. It bears some thinking about.
|
| Andrew
|

Ville Voutilainen

unread,
Oct 29, 2013, 12:48:03 PM10/29/13
to conc...@isocpp.org
On 29 October 2013 17:13, Gabriel Dos Reis <g...@axiomatics.org> wrote:
| Yes, and the overload could conceivably implement non-Boolean
| semantics, which creates a nice hole in the logic.

Hmm, I don't remember we decided that "concept" would return or evaluate
to anything other than a bool, so I am puzzled by this mysterious Y.



I haven't seen such a design, and the implementation refuses concepts that
declare anything else than bool as their return type. 

Andrew Sutton

unread,
Oct 29, 2013, 12:57:01 PM10/29/13
to conc...@isocpp.org
This doesn't have anything to do with declaring concepts. It's a
separate issue.

is_foo<T>() and is_bar<T>() could be constexpr functions returning
some non-bool type X for which && is overloaded. Using those in a
conjunction in a constraint is "interesting".

The compiler-defined semantics associated with && and || for comparing
constraints may not agree with the semantics implemented by the
overloaded &&. That would potentially create a hole in the logic.

I've been aware of this issue for a long time. That's why the wording
says that user-defined overloads are not considered when processing
(typing) constraints.

Andrew Sutton

Gabriel Dos Reis

unread,
Oct 29, 2013, 2:11:07 PM10/29/13
to conc...@isocpp.org
Andrew Sutton <andrew....@gmail.com> writes:

| This doesn't have anything to do with declaring concepts. It's a
| separate issue.
|
| is_foo<T>() and is_bar<T>() could be constexpr functions returning
| some non-bool type X for which && is overloaded. Using those in a
| conjunction in a constraint is "interesting".

I've always understood that we were sticking with bool (which is also
why dropping 'concept' in place of 'constexpr' was a no-brainer and the
argument that won me over for 'concept bool'), and didn't see any good
motivating examples of anything from the Palo Alto TR to sway me away
the simplicity. I would stick to that until we need the extra complexity.

Botond Ballo

unread,
Oct 29, 2013, 2:26:09 PM10/29/13
to conc...@isocpp.org, g...@axiomatics.org
On Tuesday, October 29, 2013 2:11:07 PM UTC-4, Gabriel Dos Reis wrote:
Andrew Sutton <andrew....@gmail.com> writes:

| This  doesn't have anything to do with declaring concepts. It's a
| separate issue.
|
| is_foo<T>() and is_bar<T>() could be constexpr functions returning
| some non-bool type X for which && is overloaded. Using those in a
| conjunction in a constraint is "interesting".

I've always understood that we were sticking with bool (which is also
why dropping 'concept' in place of 'constexpr' was a no-brainer and the
argument that won me over for 'concept bool'), and didn't see any good
motivating examples of anything from the Palo Alto TR to sway me away
the simplicity.  I would stick to that until we need the extra complexity.

I think the situation Richard and Andrew are talking about is something like the following:

struct Y {};

constexpr bool operator&&(bool, Y);

template <typename T>
constexpr bool is_foo();  // not a concept

template <typename T>
constexpr Y is_bar();     // not a concept

template <typename T>
concept bool Concept1()
{
   
return is_foo<T>();
}

template <typename T>
concept bool Concept2()
{
   
return is_foo<T>() && is_bar<T>();
}

template <Concept1 C>
void f(C);

template <Concept2 C>
void f(C);

int main()
{
    // Say 'is_foo<FooBar>()' and
   
// 'is_foo<FooBar>() && is_bar<FooBar>()'
    // are both true.

   
FooBar x;  

    // Does overload resolution succeed here and call
    // the Concept2 overload of f?
    f
(x);
}



Regards,
Botond

Andrew Sutton

unread,
Oct 29, 2013, 2:32:16 PM10/29/13
to conc...@isocpp.org, Gabriel Dos Reis
> I think the situation Richard and Andrew are talking about is something like
> the following:

...

Right. I was just typing something very similar, down to the "not a
concept" comments :)

I think with the current wording, this would be ill-formed since the
overload would not be found and Y does not not contextually convert to
bool. The error is detected when constraints were synthesized for the
shorthand Concept2.

The alternative that I suggested was that this would be allowed but
the expression is_foo<T>() && is_bar<T>() would be treated as atomic
because && resolves to a user-defined function.

Andrew

Gabriel Dos Reis

unread,
Oct 29, 2013, 2:46:00 PM10/29/13
to Botond Ballo, conc...@isocpp.org
Thanks. As I said in another message, this never occured to me to be
part of the model we have been working with -- for we had had
discussions and one of the key arguments that won me over for 'concept bool'
was that during a transition period people would just drop 'concept' in
place of 'constexpr' in constraints definition. That argument would
no longer hold if we suddently allowed mysterious Ys. And I don't seem
to recall a recent discussion about allowing things other than 'bool' as
return type. I believe that would be straining away from simplicity, adding
complexity, irregularities, and more special rules for no obvious
benefit I can relate to, looking at the Palo Alto TR.

So, for all practical purposes, I will continue to believe we don't have
mysterious Ys, and that we don't have additional rules that say only
builtin operators are considered :-)

-- Gaby

Botond Ballo

unread,
Oct 29, 2013, 2:53:50 PM10/29/13
to conc...@isocpp.org, Botond Ballo, g...@axiomatics.org

The current proposal allows *any constant expression* in a requires-clause.
'is_bar<T>() && is_foo<T>()' in my example above is a perfectly valid
constant expression.

Are you proposing that what we allow in a requires-clause be more
restricted (for example, to only concepts)?

Regards,
Botond

Gabriel Dos Reis

unread,
Oct 29, 2013, 3:29:22 PM10/29/13
to Botond Ballo, conc...@isocpp.org
I am not sure I am proposing something new, as opposed to explaining
what my understanding has been since the beginning.

The first thing I should say upfront is that I don't remember we decided
on predicates involved in template definitions to be anything other than
bona fide predicates (pure constant expression functions with 'bool' return
type) and 'concept' applications (when we have concepts.)

The second thing is that the purpose of 'concepts lite' is to help us
(users) and the tools make sense of template definitions and uses. The
way we decided to do this is by standing firm on the centuries-old rocks
of propositional logic, and possibly adequate subset of first order
logic as appropriate for practical C++ (think axioms.)

Third, I do not believe that we will achieve our goal of making sense
of template uses/definition by dumping arbitrary expression of type bool
or convertible to bool (programming goo) on the current template
machinery. So, I do expect some restrictions -- for, bringing structure
means that something will have to give. Otherwise, we would make a complex
situation worse. I am sure, there are arguments "against" restricting
what expressions/statements we can use in a concpet (lite) definition.
My view is that our goal is to bring structure, not chaos; and for
the most part, simple bool-valued constant expressions are sufficient
for most practical purposes. Again, I'm looking at the Palo Alto TR.
We have to make it work elegantly with minimal surface complexity and
intellectual overhead.

-- Gaby

Botond Ballo

unread,
Oct 29, 2013, 3:43:58 PM10/29/13
to conc...@isocpp.org, Botond Ballo, g...@axiomatics.org
On Tuesday, October 29, 2013 3:29:22 PM UTC-4, Gabriel Dos Reis wrote:
Botond Ballo <botond...@gmail.com> writes:

|     Botond Ballo <botond...@gmail.com> writes:
|     | struct Y {};
|     |
|     | constexpr bool operator&&(bool, Y);
|     |
|     | template <typename T>
|     | constexpr bool is_foo();  // not a concept
|     |
|     | template <typename T>
|     | constexpr Y is_bar();     // not a concept
|     |
|     | template <typename T>
|     | concept bool Concept1()
|     | {
|     |    return is_foo<T>();
|     | }
|     |
|     | template <typename T>
|     | concept bool Concept2()
|     | {
|     |     return is_foo<T>() && is_bar<T>();
|     | } 
  The first thing I should say upfront is that I don't remember we decided
on predicates involved in template definitions to be anything other than
bona fide predicates (pure constant expression functions with 'bool' return
type) and 'concept' applications (when we have concepts.)
 
Is Concept2 in the code above not a bona fide predicate? It's a pure
constant expression function with a 'bool' return type.

The only question is whether, for overloading purposes, we treat it
as being a single atomic proposition, or the conjunction of two
atomic propositions. If 'is_bar' returned bool, then the current
proposal unambiguously treats is as a conjunction of two atomic
propositions. The question is whether the fact the 'is_bar'
returns Y rather than bool, should change that.

Regards,
Nate

Gabriel Dos Reis

unread,
Oct 29, 2013, 3:58:05 PM10/29/13
to conc...@isocpp.org, Botond Ballo
I am not seeing an 'overloading' problem or an 'overloading purpose' issue.
If we can't make sense of 'is_bar<T>()' as a bona fide predicate (the
return type isn't bool), then the definition is playing out of the
league. It isn't an overloading issue. I don't think what I am saying
is new from what I said earlier. Please do consider this in the larger
context I provided in my earlier message. Don't pick it in isolation.

-- Gaby

Botond Ballo

unread,
Oct 29, 2013, 5:11:04 PM10/29/13
to conc...@isocpp.org, Botond Ballo, g...@axiomatics.org

What do you mean by "the definition is playing out of the league"?
Do you mean that defining Concept2 like so:



template <typename T>
concept bool Concept2()
{
   
return is_foo<T>() && is_bar<T>();
}

shouldn't be allowed at all because one of the conjuncts is not a bone fide predicate?

As far as I understand, the Concepts Lite proposal makes no restrictions on what is allowed to go inside the definition of a concept, other than that the whole expression must be boolean (and a compile-time constant). The only time when the sub-structure of the expression becomes relevant, is when we are doing overloading and trying to determine whether one constraint subsumes another.

Regards,
Botond

Gabriel Dos Reis

unread,
Oct 29, 2013, 10:19:22 PM10/29/13
to Botond Ballo, conc...@isocpp.org
Yes -- I already explained this in the past 2 or 3 messages.

| As far as I understand, the Concepts Lite proposal makes no restrictions on
| what is allowed to go inside the definition of a concept, other than that the
| whole expression must be boolean (and a compile-time constant). The only time
| when the sub-structure of the expression becomes relevant, is when we are doing
| overloading and trying to determine whether one constraint subsumes another.

As I've said before, this isn't an "overloading" issue; looking at it
that way is a compiler-implementation leakage into specification.

-- Gaby

Botond Ballo

unread,
Oct 29, 2013, 10:35:39 PM10/29/13
to conc...@isocpp.org, Botond Ballo, g...@axiomatics.org
On Tuesday, October 29, 2013 10:19:22 PM UTC-4, Gabriel Dos Reis wrote:
|     |     |     Botond Ballo <botond...@gmail.com> writes:
|     |     |     | struct Y {};
|     |     |     |
|     |     |     | constexpr bool operator&&(bool, Y);
|     |     |     |
|     |     |     | template <typename T>
|     |     |     | constexpr bool is_foo();  // not a concept
|     |     |     |
|     |     |     | template <typename T>
|     |     |     | constexpr Y is_bar();     // not a concept

| Do you mean that defining Concept2 like so:
|
| template <typename T>
| concept bool Concept2()
| {
|     return is_foo<T>() && is_bar<T>();
| }
|
| shouldn't be allowed at all because one of the conjuncts is not a bone fide
| predicate?

Yes -- I already explained this in the past 2 or 3 messages.

Ok, what about the following concept:

template  <typename T>
concept bool Small()
{
   
return sizeof(T) < 8;
}

Should this be allowed?

If yes, then what exactly is the restriction you envision on concept definitions that allows Small but disallows Concept2? "If the top-level operator in the return expression is && or || then both operands shall have type bool"? Doesn't that seem a little arbitrary?

If not, then how do you implement a constraint that has the behaviour of Small? Do you always have to delgate to a non-concept helper function?

Regards,
Botond

Andrew Sutton

unread,
Oct 30, 2013, 8:05:29 AM10/30/13
to conc...@isocpp.org, Botond Ballo, Gabriel Dos Reis
> Ok, what about the following concept:
>
> template <typename T>
> concept bool Small()
> {
> return sizeof(T) < 8;
> }
>
> Should this be allowed?

Of course. The expression is atomic. The result type of < is bool, so
it could also be combined with other predicates (returning bool).

Andrew

Botond Ballo

unread,
Oct 30, 2013, 11:24:13 AM10/30/13
to conc...@isocpp.org, Botond Ballo, Gabriel Dos Reis

Oh, I know the Concepts Lite proposal allows it. I was curious whether Gaby thought it should be allowed, given that he thought

template <typename T>
concept bool Concept2()
{
   
return is_foo<T>() && is_bar<T>();
}

(where is_bar<T>() returns a non-boolean type and the && is overloaded), which the Concepts Lite proposal also allows, should not be allowed.

Regards,
Botond

Andrew Sutton

unread,
Oct 30, 2013, 11:30:43 AM10/30/13
to conc...@isocpp.org, Botond Ballo, Gabriel Dos Reis
> Oh, I know the Concepts Lite proposal allows it. I was curious whether Gaby
> thought it should be allowed, given that he thought
>
> template <typename T>
> concept bool Concept2()
> {
> return is_foo<T>() && is_bar<T>();
> }
>
> (where is_bar<T>() returns a non-boolean type and the && is overloaded),
> which the Concepts Lite proposal also allows, should not be allowed.

Hopefully, I'm not putting words in Gaby's mouth, but I suspect that
it is because the example is not obviously representative of the kinds
of things that should be in a concept.

I think if you provide a meaningful use case rather than unfocused
example, it will be easier to motivate a serious discussion of what
should be allowed and what should not.

Andrew

Gabriel Dos Reis

unread,
Oct 30, 2013, 12:36:47 PM10/30/13
to Botond Ballo, conc...@isocpp.org
Botond Ballo <botond...@gmail.com> writes:

| On Tuesday, October 29, 2013 10:19:22 PM UTC-4, Gabriel Dos Reis wrote:
|
| | | | Botond Ballo <botond...@gmail.com> writes:
| | | | | struct Y {};
| | | | |
| | | | | constexpr bool operator&&(bool, Y);
| | | | |
| | | | | template <typename T>
| | | | | constexpr bool is_foo(); // not a concept
| | | | |
| | | | | template <typename T>
| | | | | constexpr Y is_bar(); // not a concept
|
| | Do you mean that defining Concept2 like so:
| |
| | template <typename T>
| | concept bool Concept2()
| | {
| | return is_foo<T>() && is_bar<T>();
| | }
| |
| | shouldn't be allowed at all because one of the conjuncts is not a bone
| fide
| | predicate?
|
| Yes -- I already explained this in the past 2 or 3 messages.
|
|
| Ok, what about the following concept:
|
| template <typename T>
| concept bool Small()
| {
| return sizeof(T) < 8;
| }
|
| Should this be allowed?

It has always been allowed, even in the previous concept iteration.
I am puzzled that you would think there is a problem with it.

| If yes, then what exactly is the restriction you envision on concept
| definitions that allows Small but disallows Concept2? "If the top-level
| operator in the return expression is && or || then both operands shall have
| type bool"? Doesn't that seem a little arbitrary?

If you mean the question to be hetorical, then obviously you are not
expecting an answer; you may not even be expecting a conversation.

Any restriction will look abritrary to someone. But there ought to be
restrictions; so if the question isn't rhetorical, I don't now what to
make of it or how useful it is.

No, I am not thinking in terms of "toplevel operator". We have always
be using simple, standard notion of predicate in (typed) first order
logic: formula are either application of predicates to arguments (terms),
variables or constants of type bool, combination of formula with
standard logical operators. This stuff is standard -- as I indicated in
previous messages.

| If not, then how do you implement a constraint that has the behaviour
| of Small? Do you always have to delgate to a non-concept helper function?

What do you mean by "delagate"? When the concept Small is applied to
argument, it becomes an atomic formula.

-- Gaby

Gabriel Dos Reis

unread,
Oct 30, 2013, 12:38:20 PM10/30/13
to Botond Ballo, conc...@isocpp.org
There is no relationship between is_bar and Small, so maybe you know
where you are driving that, but you are not communicating it.
I've already explained the issue with is_bar.

-- Gaby

Gabriel Dos Reis

unread,
Oct 30, 2013, 12:40:55 PM10/30/13
to Andrew Sutton, conc...@isocpp.org, Botond Ballo
Andrew Sutton <andrew....@gmail.com> writes:

| > Oh, I know the Concepts Lite proposal allows it. I was curious whether Gaby
| > thought it should be allowed, given that he thought
| >
| > template <typename T>
| > concept bool Concept2()
| > {
| > return is_foo<T>() && is_bar<T>();
| > }
| >
| > (where is_bar<T>() returns a non-boolean type and the && is overloaded),
| > which the Concepts Lite proposal also allows, should not be allowed.
|
| Hopefully, I'm not putting words in Gaby's mouth,

You are not.

| but I suspect that it is because the example is not obviously
| representative of the kinds of things that should be in a concept.

Indeed. I've articulated the guidelines in a previous messages; but
follow discussions appear to be focused on implementation details instead
of looking at the criteria first.

Loïc Joly

unread,
Oct 30, 2013, 5:48:13 PM10/30/13