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/.
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…
| However, currently it's possible to useFill that under 'implementation details of current concept lites' :-)
| constexpr bool functions as constraints, and those _can_ be specialized.
On Sun, Oct 27, 2013 at 9:40 AM, Ville VoutilainenVille, have you really tried to define a constexpr bool function
<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.
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.
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.
Hi,
if a concept is always boolean function, isn't bool redundant?
|We don't evaluate the condition before values are provided for the
| 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.
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.
Well, this is what it means to check template definitions :-)|
| 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.
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>;Looks more clear to me, like a term-rewriting.
} && requires Input_iterator<T>;
> Why? Because we don't want concepts to have a wildly different syntaxThis thread starts with "a wildly different" syntax, so it appears that
> compared to existing facilities.
some people want.
> That eases the implementation, andAndrew says (to me, on cppnow) Concepts should be defined in a
> 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.
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 aboutThen what you may want to care about is what a constrained
> unconstrained
> existing code and constrained new code. I prefer having a minimized
> difference
> between them.
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 :)
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 ... };
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.
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`.
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, and the overload could conceivably implement non-BooleanHmm, I don't remember we decided that "concept" would return or evaluate
| semantics, which creates a nice hole in the logic.
to anything other than a bool, so I am puzzled by this mysterious Y.
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.
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);
}
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>();
| | }
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.)
template <typename T>
concept bool Concept2()
{
return is_foo<T>() && is_bar<T>();
}
| | | 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.
template <typename T>
concept bool Small()
{
return sizeof(T) < 8;
}
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.As much as I hate pointing people to wikipedia, maybe it might be useful:
http://en.wikipedia.org/wiki/First-order_logic
-- Gaby
thefore the expression is_foo<T>() && is_bar<T>()
isn't acceptable.
All I have I been saying for n messages is that it is the former
| 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.
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
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'.)
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 }---
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.