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
to conc...@isocpp.org
Le 29/10/2013 19:32, Andrew Sutton a �crit :
I believe that a part of the problem is that && and || get a special
meaning at the top level of concept definition. I'm wondering if you
tried other syntaxes to combine predicates?

---
Lo�c

Gabriel Dos Reis

unread,
Oct 30, 2013, 5:53:07 PM10/30/13
to conc...@isocpp.org
Loïc Joly <loic.act...@numericable.fr> writes:
Can someone explain why the focus on "toplevel"?

-- Gaby

Botond Ballo

unread,
Oct 30, 2013, 6:34:30 PM10/30/13
to conc...@isocpp.org, g...@axiomatics.org

Well, I assume you wouldn't object to


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

where f is a constexpr function that returns bool. Here, an expression of the sort that offends you (&& where one of the operands is not bool) appears, but not at the top level.

Regards,
Botond

Loïc Joly

unread,
Oct 30, 2013, 6:36:16 PM10/30/13
to conc...@isocpp.org
Le 30/10/2013 22:53, Gabriel Dos Reis a �crit :
> |
> | I believe that a part of the problem is that && and || get a special
> | meaning at the top level of concept definition. I'm wondering if you
> | tried other syntaxes to combine predicates?
>
> Can someone explain why the focus on "toplevel"?
>

Maybe because I misunderstood the wording... I was under the impression
that && may appear both inside an atomic proposition and outside of it
(which I called top level). And that the meaning is quite different in
both cases. Am I wrong?

---
Lo�c

Gabriel Dos Reis

unread,
Oct 30, 2013, 6:48:11 PM10/30/13
to Botond Ballo, conc...@isocpp.org
Here, if I understand your description of 'f' correctly, it is a
predicate symbol, therefore f(...) is an atomic formula.

Phrasing the issue in terms of 'toplevel' and 'non-toplevel' offers a
low-level implementation view, and I don't think it helps understanding
what we are trying to achieve.

In any logical framework, we need logical operators and combinators.
We decided to use centuries-old predicate logic where 'not', 'and', and
'or' are the basic logical operators. This is standard stuff, that is
thought in upper elementary schools, or middle schools.

As much as I hate pointing people to wikipedia, maybe it might be useful:

http://en.wikipedia.org/wiki/First-order_logic

-- Gaby

Botond Ballo

unread,
Oct 30, 2013, 7:06:03 PM10/30/13
to conc...@isocpp.org, Botond Ballo, g...@axiomatics.org

I was trying to use a term that wasn't ambiguous - it's clear what expression is at the top level and what is not.

On the other hand, what is an atomic proposition and what isn't is something that's up to us to define in the Concepts Lite proposal. One suggestion (Andrew's, above) was that 'a && b' could be an atomic proposition if one of a or b weren't boolean.

Regards,
Botond

Richard Smith

unread,
Oct 30, 2013, 7:20:21 PM10/30/13
to conc...@isocpp.org, Botond Ballo
I think you've misunderstood the issue here, and your response could be interpreted as being quite patronizing. Such antagonism is unlikely to lead to a productive discussion.

The problem is that we have two different meanings of && within a constraint. One is from formal logic (where it operates on boolean terms) and the other is from C++ (where it operates on expressions that need not be of a boolean type), and the syntax

  is_foo<T>() && is_bar<T>()

for a predicate is ambiguous: it might mean the conjunction of is_foo<T>() and is_bar<T>(), or it might mean something like "operator&&(is_foo<T>(), is_bar<T>())" -- the latter would clearly be an atomic proposition, just as "f(is_foo<T>(), is_bar<T>())" is.

If we wished to allow && to be used as either operation, this ambiguity could be resolved until we know the type 'T', but it seems that we need to decide whether the constraint is

  Atom{is_foo<T>()} /\ Atom{is_bar<T>()}

or

  Atom{is_foo<T>() && is_bar<T>()}

without knowing T, in order to perform template partial ordering.
 
As much as I hate pointing people to wikipedia, maybe it might be useful:

  http://en.wikipedia.org/wiki/First-order_logic

-- Gaby

Gabriel Dos Reis

unread,
Oct 30, 2013, 7:52:10 PM10/30/13
to conc...@isocpp.org
There is no antagonism and I've asked several times that people explain what
the problem really is. I've also explained several times why is_bar isn't
a predicate, and the reason I believe that. Any statement of
'anatgonism' and/or 'patronizing', after repeated clarifications and
asking people to explain, like in your case where you believe I
misunderstand the issue is, in my view, being designed to manifacture
claimed antagonism.

| The problem is that we have two different meanings of && within a constraint.

Correct; and I've said that in concepts, the one we are looking at is
from simple centuries-old predicate logic using C++.

| One is from formal logic (where it operates on boolean terms) and the other is
| from C++ (where it operates on expressions that need not be of a boolean type),
| and the syntax
|
|   is_foo<T>() && is_bar<T>()
|
| for a predicate is ambiguous:

And I have been saying that any such notion of ambiguity is only
artificial, and does not exist: for the operand is_bar<T>() isn't any
a predicate (even if the mysterious Y could be made to user-defined
covnersion to bool), thefore the expression is_foo<T>() && is_bar<T>()
isn't acceptable.

| it might mean the conjunction of is_foo<T>() and
| is_bar<T>(), or it might mean something like "operator&&(is_foo<T>(), is_bar<T>
| ())" -- the latter would clearly be an atomic proposition, just as "f(is_foo<T>
| (), is_bar<T>())" is.
|
| If we wished to allow && to be used as either operation, this ambiguity could
| be resolved until we know the type 'T', but it seems that we need to decide
| whether the constraint is
|
|   Atom{is_foo<T>()} /\ Atom{is_bar<T>()}
|
| or
|
|   Atom{is_foo<T>() && is_bar<T>()}
|
| without knowing T, in order to perform template partial ordering.

All I have I been saying for n messages is that it is the former
interpretation: we are defining a predicate over a parameter, which by
definition is unknown. So we cannot put ourselves in a position where
we have to wait till we know the value of 'T' before we can even start
processing correctly the logical structure of the definition of the predicate.

I confess I'm very surprised you find that patronizing.

(And parenthestically, I don't think I misunderstood. We may disagree on
what the resolution should be; but is a whole different thing.)

Gabriel Dos Reis

unread,
Oct 30, 2013, 7:55:41 PM10/30/13
to Botond Ballo, conc...@isocpp.org
We want to know the logical structure of the predicate without having to
know the actual values of the atomic formulae.

-- Gaby

Richard Smith

unread,
Oct 30, 2013, 9:59:02 PM10/30/13
to conc...@isocpp.org
OK, I think this is the key: how do you tell whether is_bar<T>() (or any arbitrary expression) is a predicate? In the general case, the type of such an expression will be dependent.

For instance, given:

  template<typename T> constexpr typename enable_if<something<T>(), bool>::type thing() { ... }
  template<typename T> constexpr typename enable_if<!something<T>(), bool>::type thing() { ... }

would you consider thing<T>() to be a predicate?
 
thefore the expression is_foo<T>() && is_bar<T>()
isn't acceptable.

| it might mean the conjunction of is_foo<T>() and
| is_bar<T>(), or it might mean something like "operator&&(is_foo<T>(), is_bar<T>
| ())" -- the latter would clearly be an atomic proposition, just as "f(is_foo<T>
| (), is_bar<T>())" is.
|
| If we wished to allow && to be used as either operation, this ambiguity could
| be resolved until we know the type 'T', but it seems that we need to decide
| whether the constraint is
|
|   Atom{is_foo<T>()} /\ Atom{is_bar<T>()}
|
| or
|
|   Atom{is_foo<T>() && is_bar<T>()}
|
| without knowing T, in order to perform template partial ordering.

All I have I been saying for n messages is that it is the former
interpretation: we are defining a predicate over a parameter, which by
definition is unknown.  So we cannot put ourselves in a position where
we have to wait till we know the value of 'T' before we can even start
processing correctly the logical structure of the definition of the predicate.

I confess I'm very surprised you find that patronizing.

(And parenthestically, I don't think I misunderstood.  We may disagree on
what the resolution should be; but is a whole different thing.)

|  
|
|     As much as I hate pointing people to wikipedia, maybe it might be useful:
|
|       http://en.wikipedia.org/wiki/First-order_logic
|
|     -- Gaby

Gabriel Dos Reis

unread,
Oct 30, 2013, 11:23:00 PM10/30/13
to conc...@isocpp.org
Note that this isn't new in my communications.

| how do you tell whether is_bar<T>() (or any arbitrary expression) is a
| predicate? In the general case, the type of such an expression will be
| dependent.

For an arbitrary expression in arbitrary templates, absolutely.

However, the whole point of being a predicate is that is_bar<T>() is
required to have has type 'bool'. The formal of the predicate
is 'T'. And we know the result must be 'true' of 'false'. Not that
when one does further arbitrary computation on the result of is_bar<T>()
one might possibly get a bool.

Please, do keep in mind what I've said several times in this discussion
about 'concept bool'.

People complained, and keep complaining, that 'bool' is redundant in
'concept bool'. I would agree. Except in the concepts lite design,
there is a design goal to allow people to migrate from using constexpr
bool functions to concepts lite (that define constraints) by replacing
'constexpr' with 'concept'. I've said this in several past messages.
Look at TCPL++4 for examples of what I am talking about.

In concept constraints, one usually has only application of concepts
which yield 'bool' values. In C++11, where concept are absent, we can
achieve a good simulation (to some extent) if we are disciplined enough;
that is where the 'constexpr bool' functions come from. Again, consult
TC++PL4 for examples. Now, going from this state to the place
where we have concept (which are predicates) we naturally require the
'concept functions' to have return type bool. Notice also that this is
not 'arbitrary expression'.

| For instance, given:
|
|   template<typename T> constexpr typename enable_if<something<T>(), bool>::type
| thing() { ... }
|   template<typename T> constexpr typename enable_if<!something<T>(),
| bool>::type thing() { ... }
|
| would you consider thing<T>() to be a predicate?

If 'thing's is supposed to be used in concepts, there is no mystery
about its return type. It has to be bool. There is no sugar coating it.
(In a concept world, it would be bool anyway.)

Note also that Andrew did conduct experiments on 'constraining'
constraints (the simulation of enable_if on the 'thing') and came up
with the conclusion that in *practice* there is no such thing and even
if one could conceive of it in theory it does not bring anything at all
in practice. This might be surprise you. It reinforced the dichotomy
we already suspected between 'constraints' and 'concepts'.

Also note that there is no implementation of the speculation around
'a && b' being a conjunction depending on the phase of the moon. I
fully expect the impact of such speculation on the specification (and
teachability of concepts lite) to be marred with excessive complexity --
with no tangible benefits in return.

-- Gaby

Vicente J. Botet Escriba

unread,
Oct 31, 2013, 3:21:10 AM10/31/13
to conc...@isocpp.org, Gabriel Dos Reis
Le 31/10/13 04:23, Gabriel Dos Reis a �crit :
> | On Wed, Oct 30, 2013 at 4:52 PM, Gabriel Dos Reis <g...@axiomatics.org> wrote:
> |
>
>
> Please, do keep in mind what I've said several times in this discussion
> about 'concept bool'.
>
> People complained, and keep complaining, that 'bool' is redundant in
> 'concept bool'. I would agree. Except in the concepts lite design,
> there is a design goal to allow people to migrate from using constexpr
> bool functions to concepts lite (that define constraints) by replacing
> 'constexpr' with 'concept'. I've said this in several past messages.
> Look at TCPL++4 for examples of what I am talking about.
Salut Gaby,

Je t�envoie ce mail a toi personnellement.

Cordialement,
Vicente

If this is the only reason, as the user would need to replace constexpr
by concept, s/he could replace constexpr bool by concept as well isn't it?
At the end compilers could allow bool but report a warning.
By the time Concepts lite will be in the standard I expect a lot of
people will have a lots of template variables, so to help the people to
migrate to concepts the template variable form should also be supported.
No seriously, I could admit this kind of things in a prototype, but the
standard should define the grammar that is better for the new users,
which have much more trouble learning the language.



Bjarne Stroustrup

unread,
Oct 31, 2013, 9:16:22 AM10/31/13
to conc...@isocpp.org
We need "concept" to syntactically distinguish concept names for the
terse syntax, and we may/will need concepts distinguished later
when/if we want to be able to specify semantics.

Gabriel Dos Reis

unread,
Oct 31, 2013, 11:12:36 AM10/31/13
to conc...@isocpp.org
"Vicente J. Botet Escriba" <vicent...@wanadoo.fr> writes:

| Le 31/10/13 04:23, Gabriel Dos Reis a écrit :
| > | On Wed, Oct 30, 2013 at 4:52 PM, Gabriel Dos Reis <g...@axiomatics.org> wrote:
| > |
| >
| >
| > Please, do keep in mind what I've said several times in this discussion
| > about 'concept bool'.
| >
| > People complained, and keep complaining, that 'bool' is redundant in
| > 'concept bool'. I would agree. Except in the concepts lite design,
| > there is a design goal to allow people to migrate from using constexpr
| > bool functions to concepts lite (that define constraints) by replacing
| > 'constexpr' with 'concept'. I've said this in several past messages.
| > Look at TCPL++4 for examples of what I am talking about.
| Salut Gaby,
|
| Je t’envoie ce mail a toi personnellement.

Je crois que tu l'as envoyé à la liste :-)

| Cordialement,
| Vicente
|
| If this is the only reason, as the user would need to replace
| constexpr by concept, s/he could replace constexpr bool by concept as
| well isn't it?

You are correct that replacing 'constexpr bool' by 'concept' works just
fine. That means that we are still counting only 'bool' as return type
of predicates :-)

To be sure, I was not saying that that replacing 'constexpr' by
'concept' was the only reason.

| At the end compilers could allow bool but report a warning.
| By the time Concepts lite will be in the standard I expect a lot of
| people will have a lots of template variables, so to help the people
| to migrate to concepts the template variable form should also be
| supported.
| No seriously, I could admit this kind of things in a prototype, but
| the standard should define the grammar that is better for the new
| users, which have much more trouble learning the language.

I am pretty sure the particular issue of 'concept bool' isn't over yet.
That is a separate issue -- from my view, bordering largely on syntax.

-- Gaby

Bjarne Stroustrup

unread,
Nov 3, 2013, 8:48:40 AM11/3/13
to conc...@isocpp.org
On 10/30/2013 6:34 PM, Botond Ballo wrote:

If you object to the possibility of having two meanings of &&, shouldn't you object to operator overloading in general? Some people do and consider the fact that a==b can mean different things for different types of a and b in C++ an abomination that must be avoided at all cost. Similarly for a&&b even without concepts. If you don't object to operator overloading, why worry about the possibility in concepts?

Botond Ballo

unread,
Nov 3, 2013, 6:30:29 PM11/3/13
to conc...@isocpp.org, b...@cs.tamu.edu
I don't object to operator overloading, and I'm not worried about its possibility in concepts. Gaby seemed to be proposing disallowing operator overloading in certain contexts in concepts, and I was just trying to understand the scope of the proposed restriction and its motivation.

Regards,
Botond

Loïc Joly

unread,
Nov 3, 2013, 6:52:36 PM11/3/13
to conc...@isocpp.org
Le 03/11/2013 14:48, Bjarne Stroustrup a �crit :
>
> If you object to the possibility of having two meanings of &&,
> shouldn't you object to operator overloading in general? Some people
> do and consider the fact that a==b can mean different things for
> different types of a and b in C++ an abomination that must be avoided
> at all cost. Similarly for a&&b even without concepts. If you don't
> object to operator overloading, why worry about the possibility in
> concepts?

I'm not sure if I object or not. But there is a difference: Overloading
depends on the types of objects. In this case, it depend whether a
sub-part of an expression is atomic or not. This is I believe a more
subtle distinction (which in parts depends on what atomic really means),
maybe more prone to be altered by code refactoring.


>
>>
>>
>> On Wednesday, October 30, 2013 5:53:07 PM UTC-4, Gabriel Dos Reis wrote:
>>
>> Lo�c Joly <loic.act...@numericable.fr <javascript:>> writes:
>>
>> | Le 29/10/2013 19:32, Andrew Sutton a �crit :

Gabriel Dos Reis

unread,
Nov 3, 2013, 9:07:30 PM11/3/13
to conc...@isocpp.org, b...@cs.tamu.edu
Botond Ballo <botond...@gmail.com> writes:

| I don't object to operator overloading, and I'm not worried about its
| possibility in concepts. Gaby seemed to be proposing disallowing operator
| overloading in certain contexts in concepts, and I was just trying to
| understand the scope of the proposed restriction and its motivation.

Again, a characterization of what I am saying in terms of 'disallowing
overloading' misses entirely the point.

Gabriel Dos Reis

unread,
Nov 3, 2013, 9:11:38 PM11/3/13
to conc...@isocpp.org
Loïc Joly <loic.act...@numericable.fr> writes:

| Le 03/11/2013 14:48, Bjarne Stroustrup a écrit :
| >
| > If you object to the possibility of having two meanings of &&,
| > shouldn't you object to operator overloading in general? Some people
| > do and consider the fact that a==b can mean different things for
| > different types of a and b in C++ an abomination that must be
| > avoided at all cost. Similarly for a&&b even without concepts. If
| > you don't object to operator overloading, why worry about the
| > possibility in concepts?
|
| I'm not sure if I object or not. But there is a difference:
| Overloading depends on the types of objects. In this case, it depend
| whether a sub-part of an expression is atomic or not.

That is backward, and this is made possible only if one phrases the
issue in terms of overloading -- which may offer a low-level account,
but will entirely miss the point. I'm not proposing to ban overloading.
I am saying that if you have the expression 'a && b' as the body of a
constraint then 'a' and 'b' better be predicates (hence of type 'bool'.)

| This is I
| believe a more subtle distinction (which in parts depends on what
| atomic really means), maybe more prone to be altered by code
| refactoring.
|
|
| >
| >>
| >>
| >> On Wednesday, October 30, 2013 5:53:07 PM UTC-4, Gabriel Dos Reis wrote:
| >>
| >> Loďc Joly <loic.act...@numericable.fr <javascript:>> writes:

Andrew Sutton

unread,
Nov 3, 2013, 9:41:09 PM11/3/13
to conc...@isocpp.org, Bjarne Stroustrup
> | I don't object to operator overloading, and I'm not worried about its
> | possibility in concepts. Gaby seemed to be proposing disallowing operator
> | overloading in certain contexts in concepts, and I was just trying to
> | understand the scope of the proposed restriction and its motivation.
>
> Again, a characterization of what I am saying in terms of 'disallowing
> overloading' misses entirely the point.

Concepts in Concepts Lite are basically asking questions like "is this
a valid expression?", "are these types the same?", or more generally,
"is this expression true". The answers should be in the form yes or no
(true/ false). Those are the kinds of questions that Concepts Lite was
designed to answer.

I don't know how to interpret a non-bool result that overloads the
meaning of && or || in that context. What kinds of questions are you
trying ask? What kinds of concepts are you trying to define that rely
on the interpretation of user-defined functions?

I think your initial question is aimed in the wrong direction. The
question should be, "what motivation is there for allowing non-boolean
predicates in concepts?". I'd like to see that question answered.

Andrew


On Sun, Nov 3, 2013 at 9:07 PM, Gabriel Dos Reis <g...@axiomatics.org> wrote:
> Botond Ballo <botond...@gmail.com> writes:

Loïc Joly

unread,
Nov 4, 2013, 11:26:47 PM11/4/13
to conc...@isocpp.org
Le 04/11/2013 03:11, Gabriel Dos Reis a écrit :
Loïc Joly <loic.act...@numericable.fr> writes:

| Le 03/11/2013 14:48, Bjarne Stroustrup a écrit :
| >
| > If you object to the possibility of having two meanings of &&,
| > shouldn't you object to operator overloading in general? Some people
| > do and consider the fact that a==b can mean different things for
| > different types of a and b in C++ an abomination that must be
| > avoided at all cost. Similarly for a&&b even without concepts. If
| > you don't object to operator overloading, why worry about the
| > possibility in concepts?
| 
| I'm not sure if I object or not. But there is a difference:
| Overloading depends on the types of objects. In this case, it depend
| whether a sub-part of an expression is atomic or not. 

That is backward, and this is made possible only if one phrases the
issue in terms of overloading -- which may offer a low-level account,
but will entirely miss the point.  I'm not proposing to ban overloading.
I am saying that if you have the expression 'a && b' as the body of a
constraint then 'a' and 'b' better be predicates (hence of type 'bool'.)

What I'm concerned is that, if I followed correctly, the following concepts don't have the same meaning:

constexpr bool combine (bool a, bool b, bool c)
{
  return a && (b|| c);
}
template <bool a, bool b, bool c>
concept bool Concept1()
{
      return a && (b || c); // Several combined atomic propositions 
}

template <bool a, bool b, bool c>
concept bool Concept2()
{
      return combine(a, b, c); // Only one atomic proposition
}
---
Loïc

Gabriel Dos Reis

unread,
Nov 5, 2013, 12:05:10 AM11/5/13
to conc...@isocpp.org
As (logical) predicates, they both yield true (or false) on the same inputs.

-- Gaby

loic.act...@numericable.fr

unread,
Nov 5, 2013, 3:45:10 AM11/5/13
to Gabriel Dos Reis, conc...@isocpp.org

---- Message d'origine ----
>De : "Gabriel Dos Reis" <g...@axiomatics.org>
>À : conc...@isocpp.org
>Objet : Re: [concepts] N3919 - Concepts Lite - Is the syntax redundant
>Date : 05/11/2013 06:05:10 CET

>
>Loïc Joly <loic.act...@numericable.fr> writes:
>

> |
> | What I'm concerned is that, if I followed correctly, the following
> concepts
> | don't have the same meaning:
> |
> | constexpr bool combine (bool a, bool b, bool c)
> | {
> |   return a && (b|| c);
> | }
> |
> | template <bool a, bool b, bool c>
> | concept bool Concept1()
> | {
> | return a && (b || c); // Several combined atomic propositions
> | }
> |
> |
> | template <bool a, bool b, bool c>
> | concept bool Concept2()
> | {
> | return combine(a, b, c); // Only one atomic proposition
> | }
> |
>
> As (logical) predicates, they both yield true (or false) on the same
> inputs.

Although they yield the same result, they will not behave the same way in respect to overload resolution, because a class using Concept1 will be more constrained than a class that is constrainted by "a" only, but a class using Concept2 will not.

--- 
Loïc



Gabriel Dos Reis

unread,
Nov 5, 2013, 8:32:23 AM11/5/13
to loic.act...@numericable.fr, conc...@isocpp.org
Your objections seem to be moving. I don't understand this new objection:
I don't see how is has to do with "banning overloaded operators in concepts".
It is hard to aim at a moving goal post.

Consider this C++98 program fragment:

int f(int x) { return x; }
int g(int x) { return x; }

template<int pf(int)>
struct X { };

int main() {
X<f> a;
X<g> b;
return &a != &b; // #1: Do you want this to compile?
}

Even though the functions 'f' and 'g' yield the same output on the same
input, their uses as template arguments for X<> aren't equivalent.
Would you want line #1 to compile? If yes, why? If no, why? This
isn't a rhetorical question: I am trying to understand the foundational
principles of your objections.

-- Gaby

Matt Austern

unread,
Nov 5, 2013, 1:48:06 PM11/5/13
to conc...@isocpp.org, Loïc Joly
On Tue, Nov 5, 2013 at 5:32 AM, Gabriel Dos Reis <g...@axiomatics.org> wrote:
Your objections seem to be moving.  I don't understand this new objection:
I don't see how is has to do with "banning overloaded operators in concepts".
It is hard to aim at a moving goal post.

Consider this C++98 program fragment:

     int f(int x) { return x; }
     int g(int x) { return x; }

     template<int pf(int)>
     struct X { };

     int main() {
        X<f> a;
        X<g> b;
        return &a != &b;          // #1: Do you want this to compile?
     }

Even though the functions 'f' and 'g' yield the same output on the same
input, their uses as template arguments for X<> aren't equivalent.
Would you want line #1 to compile?  If yes, why?  If no, why?  This
isn't a rhetorical question: I am trying to understand the foundational
principles of your objections.

From my point of view it's not not an objection. It's just trying to understand
the basic model of Concepts Lite better, and to make sure that this aspect
is something that everyone notices. That's partly because I missed this
aspect the first time I read the paper.

The general observation is that a concept is not just a predicate. It's more
specific than that: it's a predicate written in a stylized way, by connecting
atomic predicated together using the && operator. This structure matters
for the purposes of making decisions about subsumption, which is a crucial
art of the model. The compiler is expected to make overloading decisions
based on what you might naively think of as a function's implementation
details.

Maybe this will be adequately clear to everyone. Maybe it doesn't even
matter very much if it's clear to everyone, for two reasons. First, not
everyone will be writing concepts. Second, if you don't understand the
find points and you just write things the most natural way, you'll probably
wind up with something that has the intended meaning.

That's basically my position at this point, after talking this through, and
I'm not proposing any changes. It's not surprising that other people want
to talk about this issue, though, and that part of the discussion might
involve exploring the idea of syntax to make it more obvious that
certain aspects of the internal structure of a concept have special
significance.

                                     --Matt 


Gabriel Dos Reis

unread,
Nov 6, 2013, 2:06:24 PM11/6/13
to conc...@isocpp.org, Loïc Joly

Hi Matt,
As you observed, if you write a predicate the most natural way, you will
get what you most likely expected. If you try to use a non-predicate in
a context where a predicate is expected, you will get a notice from the
compiler.

The whole sub-discussion about Concept1 not being the same as Concept2
is, in my view, pure confusion. In general, we don't except two
concepts named differently (and possibly with different definitions) to
be freely interchangeable -- just like we don't expect two structures
with different names but "similar" definition bodies to be freely
interchangeable.

The sub-discussion about atomic vs. non-atomic formulae has been far
more implementation-detail oriented than I would have wished. The most
important take-home point is this: It is desired to have template
definition refinement/specialization based on the constraints
controlling a template definition (e.g. RandomAccessIterator refines
BidirectionalIterator for sort() or std::advance()), and this refinement
is delivered naturally through predicate subsumption. Predicate
subsumption -- just like template partial ordering (e.g. is this
template more specialized than that template) as we know today -- is a
decision that is made *without looking at the actual concrete value* used
to instantiate a template. From that point of view, you can claim there
is no "invention" here; we are just taking a well known and tested
technology and deploy it at the constraint level.

Maybe the sub-discussion about concept specialization was confused by
the syntax X<T>; I wonder whether people would have had that
same reaction if the syntax was X(T). In both cases the variable is
'T', the answer type of a predicate is 'bool', and people wouldn't have
expected the type of a binary yes/no answer to be anything but a Boolean
type.

-- Gaby

Reply all
Reply to author
Forward
0 new messages