Topic: Concepts Question


Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Tue, 6 Feb 2007 18:55:22 CST
Raw View
On 7 Feb, 00:00, "W Karas" <wka...@yahoo.com> wrote:
> On Dec 21 2006, 11:53 am, "Douglas Gregor" <doug.gre...@gmail.com>
> wrote:
> When generating an "auto" concept_map, does the compiler follow the
> general function/operator lookup rules (presumably at the point
> of template instatiation), using matches that require implicit
> conversions if closer matches are not available?
>
> Sorry if I'm asking alot of dumb questions, I certainly will find
> the time to read your proposal more carefully in the future.

In earlier proposal there was a statement saying a constraint may
match event if that require implicit conversion. But I think this
question is interesting, because in my viewpoint, a constrain is
really the opposit to overloading resolution. Although not having
implicit conversion may make concept definitions into a combinatoric
excercise, or a horrific task. :-)

Regards,
Roger

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Sat, 10 Feb 2007 19:02:00 GMT
Raw View
pongba@gmail.com wrote:
>
> On Jan 6, 12:26 am, Thorsten Ottosen <thorsten.otto...@dezide.com>
> wrote:

>>Consider a container concept
>>
>>auto concept container<typename T>
>>{
>>   typename  value_type;
>>   void T::push_back( value_type );
>>
>>};This could generate the following concept_map for a container X:
>>
>>template< class T >
>>where convetible<T,X::value_type>
>>void container<X>::push_back( T&& r )
>>{
>>  X::push_back( std::forward(r) );

Correction:

   X::push_back( std::forward<T>(t) );

>>}This way
>>
>>- the most efficient function in X is always called
>>- the concept does not have to worry about perfect forwarding (which
>>would be an even bigger problem for multiple arguments)
>>
>>IOW, the concept function arguments do, by default, *never* interfere
>>with lvalue/rvalue/constness properties of the actual arguments.
>
>
> Looks like a great idea.
> One more problem though: What if I want to articulate that there
> should only be the lvalue version of push_back? According to your
> proposal, there'd be no way to do that.

Actually I imagine the following

T ==> T&&
T& ==> T&
T&& ==> T&&

for all non-reference types T.

Thus, instead of defaulting to T ==> const T&, the default would
be T ==> T&&.

This means there would be no way to pass an argument by value, but
why would you want that anyway?

-Thorsten

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: pongba@gmail.com
Date: Mon, 29 Jan 2007 10:20:41 CST
Raw View

On Jan 6, 12:26 am, Thorsten Ottosen <thorsten.otto...@dezide.com>
wrote:
> Thorsten Ottosen wrote:
> > Douglas Gregor wrote:
>
> >> Thorsten Ottosen wrote:
> > Ok. I was thinking that perhaps the generated signature would be as
> > follows:Let me try to give a better example of the forwarding capabilities of
> concepts.
>
> Consider a container concept
>
> auto concept container<typename T>
> {
>    typename  value_type;
>    void T::push_back( value_type );
>
> };This could generate the following concept_map for a container X:
>
> template< class T >
> where convetible<T,X::value_type>
> void container<X>::push_back( T&& r )
> {
>   X::push_back( std::forward(r) );
>
> }This way
>
> - the most efficient function in X is always called
> - the concept does not have to worry about perfect forwarding (which
> would be an even bigger problem for multiple arguments)
>
> IOW, the concept function arguments do, by default, *never* interfere
> with lvalue/rvalue/constness properties of the actual arguments.

Looks like a great idea.
One more problem though: What if I want to articulate that there
should only be the lvalue version of push_back? According to your
proposal, there'd be no way to do that.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Tue, 30 Jan 2007 14:51:10 CST
Raw View
On Jan 11, 2:55 am, "per...@gmail.com" <per...@gmail.com> wrote:
> 1) Then, it would allow constraining templates to scalar (~POD) or
> class types. Or maybe this should be an illegal constraint?

It might make sense to have a POD constraint, because there are
certain optimizations that work on PODs but not other class types.

> 2) Std::allocator have not yet a concept specification. Is it because
> there haven't been time to specify it, or because std::allocator don't
> fits very well in a concept[*]?

We haven't had the time to work on it, and one of the features that it
will likely rely on (associated templates) is not yet implemented in
ConceptGCC. Plus, the C++ Library Working Group has talked about an
allocator redesign for *years*, and we're hoping that such a redesign
will happen with concepts :)

> 4) The case when concepts helps compiler generating internal glue code
> (such as for the for() and possible switch()?) is another fantastic
> side of concepts. I even think this mechanism become more powerful if
> scalar and class types would be separable via axioms,

I'm having a hard time understanding why we want to separate scalar
and class types. Much of the power of the C++ template system comes
from its ability to handle scalar and class types in the same way,
with the same syntax.

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Tue, 6 Feb 2007 15:44:57 CST
Raw View
Hi!

I posted a follow up yesterday, but it seems to have been lost
somewhere.

On 30 Jan, 21:51, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
> On Jan 11, 2:55 am, "per...@gmail.com" <per...@gmail.com> wrote:
> > 4) The case when concepts helps compiler generating internal glue code
> > (such as for the for() and possible switch()?) is another fantastic
> > side of concepts. I even think this mechanism become more powerful if
> > scalar and class types would be separable via axioms,
>
> I'm having a hard time understanding why we want to separate scalar
> and class types. Much of the power of the C++ template system comes
> from its ability to handle scalar and class types in the same way,
> with the same syntax.
>


Some would argue that a pure object-oriented language don't make a
distinction between POD and non-POD type. This means that they think a
pure object-oriented language don't have "operator notation", only
"object notation". In the end, some commonly expression would become
awkward, because we are used with infix notation, like a + b, not
postfix expression, like add(a, b) or a.add(b).

But operator notation creates a set of primitive members in C++. Class
types can support all member attributes that scalar types have,
including data, type and function members, while programmers only
expect scalar types support a subset of those attributes, namely
operator functions (and data storage). Class types builds on top of
scalar types, both in terms of scalar permutation and richer range of
operatings.

In the end, it is about effort vs. control. If the type "flavour"
could be constrained, we get more control, but it might require more
effort in compilers. Is this control worth the effort? And do we want
more control, because we want to deprecate the pre-processor,
transferring some of its control to the C++ core?

Besides all this, there is another aspect I'm trying to find out.
Models or concept_maps allows us to separate the interface from its
data structure. That is not equivalent to separating scalar and class
types.

There are reasons we would want to separate the interface from data
structures. Vendor operating systems usually provide their own types
that are more friendly for the program, but with its own interface.
And strings, trees, arrays, hashes, dictionaries, etc. are partly
primitive types, deserving to be treated like POD-types, but shares
also common attributes (container, iterators, constructors, modifiers,
etc.)

If we compared concepts with the Interface definition language (IDL),
because both specify a manifest/protocoll with usage patterns, then C+
+ concept is expecting usage pattern to be essentially operating on a
scalar type, and the IDL would work the opposite way, where usage
pattern operate on its class type.

The concept realization, where the map is build, is some sort of
template instantiation. Is it possible to build this idea further,
even for classes?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "W Karas" <wkaras@yahoo.com>
Date: Tue, 6 Feb 2007 17:00:14 CST
Raw View
On Dec 21 2006, 11:53 am, "Douglas Gregor" <doug.gre...@gmail.com>
wrote:
.
> With "auto" concepts like LessThanComparable, the compiler will
> implicitly define concept maps when we need them. However, we're always
> free to define our own concept map, which can either use
> implicitly-generated members like operator<
>
>   concept_map LessThanComparable<X> { }; // operator< is implicitly
> generated, as above
>
> or can specify implementations of members:
>
>   concept_map LessThanComparable<X> {
>     bool operator<(X x1, X x2) {
>       return x1.equals(x2);
>     }
>   };
>
.

When generating an "auto" concept_map, does the compiler follow the
general function/operator lookup rules (presumably at the point
of template instatiation), using matches that require implicit
conversions if closer matches are not available?

Sorry if I'm asking alot of dumb questions, I certainly will find
the time to read your proposal more carefully in the future.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "W Karas" <wkaras@yahoo.com>
Date: Tue, 6 Feb 2007 17:48:36 CST
Raw View
On Jan 2, 10:00 am, "Douglas Gregor" <doug.gre...@gmail.com> wrote:
> per...@gmail.com wrote:
.
> > Unfortunately, pointer and reference to concepts are excluded in
> > current proposal.
>
> Many of us (myself included) come from an object-oriented background,
> and because of this one of the hardest things to grasp with concepts is
> that concepts are not types. In the OO world, when we want to model an
> animal, we write an Animal abstract base class and write specific kinds
> of animals (say, Beaver) as subclasses of Animal. So Animal acts as
> both a way to describe the requirements on animals (because its members
> are common to all animals) and as a way to manipulate any kind of
> animal without knowing which one ("Animal*" can point to any subclass
> of Animal, i.e., any kind of animal).
>
> Concepts work differently, because they only describe the requirements
> on types. So, a concept 'Animal' says what all animals do (in its
> members), and anything that behaves like an animal will have a "concept
> map" stating how it meets the requirements of the Animal concept. If
> you want to manipulate any kind of animal without knowing what specific
> kind of animal you have, create a template parameter 'A' and state that
> it meets the requirements of the 'Animal' concept. So, concepts
> separate the mechanism of describing the properties and behavior of
> types (concepts) from the mechanism for writing generic
> functions/classes that can act on any type that meets those properties
> (templates).
>
> Concepts support a truly different paradigm---we call it "generic
> programming"---than the existing mechanisms for object-oriented
> programming.
.

Am I wrong is seeing this argument in what you are saying:
"If concepts and concept maps were the same or had a
similar syntax to classes, this would imply that O-O and
generic programming are merely close variants of a common
idea.  But since O-O and generic programming are vastly
different, this is proof by contradiction that concepts and
classes must be very different"?

There is a strong consensus among GP experts that it is
axiomatic/intuitively obvious that GP and O-O are
very different.  This is in spite of the fact that Dr.
Stroustroup (and perhaps others) have written at
length about how, given a specific programming
problem, it can be difficult to decide whether to solve
it using templates or an O-O class hierarchy.

I think a much better dichotomy is between
"GP with implicit subtypes (aka duck types)"
(examples:  C++ templates without concepts,
and SmallTalk methods using references to
"obj") and "GP with explicit subtypes"
(examples:  C++ O-O class hierarchies
with virtual functions, and C++ templates
with concepts).  If you look around (hard)
on the web, you will find this argument made
better than I can, perhaps with different
terminology.

One concrete supporting point for my
argument:  SmallTalk is not considered
to support GP, yet it has reusable
non-intrusive container classes, which
C++ says can only be provided using
GP, not O-O.

There may be practical reasons for
concepts to be different from classes,
but these may in fact simply point
out enhancements that are needed
in class description facilities.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Tue, 6 Feb 2007 18:10:12 CST
Raw View
[To mods, if you happend to read this post before my post sent for 10
minutes ago, please take this, and delete the other. Fixed some typos,
etc. Thanks for your moderating efforts, in any case.]

Hi!
Think I must make myself more clear, in the paragraph below.

On 6 Feb, 22:44, "per...@gmail.com" <per...@gmail.com> wrote:
>
> There are reasons we would want to separate the interface from data
> structures. Vendor operating systems usually provide their own types
> that are more friendly for the program, but with its own interface.
> And strings, trees, arrays, hashes, dictionaries, etc. are partly
> primitive types, deserving to be treated like POD-types, but shares
> also common attributes (container, iterators, constructors, modifiers,
> etc.)
>

There are reasons we would want to separate the interface from its
data structure even more, than concept_map may do at scalar types. In
a cryptographic library, you template the algorithm because it varies
between ciphers, without paying attention to the underlying
transformation algebra, and with more "advanced" protocol than
iterator operators (i.e. ++, --, +=, -=) in algorithm library. And
vendor operating systems usually provide their own types, that are
more friendly for the program, but with its own interface.  And
strings, trees, arrays, hashes, dictionaries, etc. are partly
primitive types, partly shares common subprotocols/groups of
attributes (container, iterating, constructing & destructing,
modifying, etc.), but their interface differs between implementations.

Regards,
Roger

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Tue, 6 Feb 2007 18:51:13 CST
Raw View
Hi!
Think I must make myself more clear, in the paragraph below.

On 6 Feb, 22:44, "per...@gmail.com" <per...@gmail.com> wrote:
>
> There are reasons we would want to separate the interface from data
> structures. Vendor operating systems usually provide their own types
> that are more friendly for the program, but with its own interface.
> And strings, trees, arrays, hashes, dictionaries, etc. are partly
> primitive types, deserving to be treated like POD-types, but shares
> also common attributes (container, iterators, constructors, modifiers,
> etc.)
>

There are reasons we would want to separate the interface from its
data structure. In a cryptograhic library, you may template the
algorithm because it varies between ciphers, without paying attention
to the underlying transformation algebra, and with more "advanced"
protocoll than iterator operators (i.e. ++, --, +=, -=) in algorithm
library. And vendor operating systems usually provide their own types,
that are more friendly for the program, but with its own interface.
And strings, trees, arrays, hashes, dictionaries, etc. are partly
primitiv types, partly shares common subprotocols/groups of attributes
(container, iterating, constructing & destructing, modifying, etc.),
but their interface differs between implementations.

Regards,
Roger

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Mon, 8 Jan 2007 16:08:06 CST
Raw View
perrog@gmail.com wrote:
> Such a hypothetical class concept would be some sort of protocol or
> class outline, that 1) is empty in that it has no type-name; 2)
> contains only non-data members and 3) a constrained template must be a
> class-type. The name of the concept would represent the protocol, and
> not a type-name.

What benefits would this kind of "protocol" have over a concept?

> >
> > One problem with the code above is that the syntax can get rather
> > clunky. What if we want to constrain T[N]?
> >
> >   template<typename T, std::size_t N>
> >   concept_map Constraint<T[N]> {
> >     iterator T[N]::begin() { return this; }
> >     iterator T[N]::end() { return this + N; }
> >   };
> >
> > Or maybe that should be:
> >
> >   template<typename T, std::size_t N>
> >   concept_map Constraint<T[N]> {
> >     iterator T::begin()[N] { return this; }
> >     iterator T::end()[N] { return this + N; }
> >   };
> >
> > ?
> >
> > C++'s declarator syntax is really scary as-is; extending it to deal
> > with non-trivial nested name specifiers like the array type T[N] might
> > be more trouble than its worth. We're already told to "prefer free
> > functions to member functions"... perhaps the same should be true of
> > concepts?
>
> What is it really being constrained? The element T, or the array
> containing elements of T?

We're constraining the array, because we want to be able to get begin
and end iterators for any array.
(For reference, that "Constrain" concept above is actually called "For"
in the paper on using concepts for the range-based "for" loop,
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf, and
it is crucial that we be able to support arrays.)

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Thu, 11 Jan 2007 01:55:50 CST
Raw View
Douglas Gregor skrev:

> perrog@gmail.com wrote:
> > Such a hypothetical class concept would be some sort of protocol or
> > class outline, that 1) is empty in that it has no type-name; 2)
> > contains only non-data members and 3) a constrained template must be a
> > class-type. The name of the concept would represent the protocol, and
> > not a type-name.
>
> What benefits would this kind of "protocol" have over a concept?
0) To start with, I wasn't really trying to give rice and rose. :-)

1) Then, it would allow constraining templates to scalar (~POD) or
class types. Or maybe this should be an illegal constraint?

2) Std::allocator have not yet a concept specification. Is it because
there haven't been time to specify it, or because std::allocator don't
fits very well in a concept[*]?

3) Protocols is not more revolutionising than just abbreviating the set
of member requirements protocol[**], and the set of scalar requirements
concept. The main difference would supposedly be how concept_maps
instantiate the concept (and perhaps writing class in the concept
definition.)

4) The case when concepts helps compiler generating internal glue code
(such as for the for() and possible switch()?) is another fantastic
side of concepts. I even think this mechanism become more powerful if
scalar and class types would be separable via axioms,

5) Another point that requires massive text explanation.

[*]: The C++ library crypto++ make even more use of class template
parameters than STL does, http://www.cryptopp.com/.

[**]: Some C++ experts term member constraints policies.

>
> > >
> > > One problem with the code above is that the syntax can get rather
> > > clunky. What if we want to constrain T[N]?
> > >
> > >   template<typename T, std::size_t N>
> > >   concept_map Constraint<T[N]> {
> > >     iterator T[N]::begin() { return this; }
> > >     iterator T[N]::end() { return this + N; }
> > >   };
> > >
> > > Or maybe that should be:
> > >
> > >   template<typename T, std::size_t N>
> > >   concept_map Constraint<T[N]> {
> > >     iterator T::begin()[N] { return this; }
> > >     iterator T::end()[N] { return this + N; }
> > >   };
> > >
> > > ?
> > >
> > > C++'s declarator syntax is really scary as-is; extending it to deal
> > > with non-trivial nested name specifiers like the array type T[N] might
> > > be more trouble than its worth. We're already told to "prefer free
> > > functions to member functions"... perhaps the same should be true of
> > > concepts?
> >
> > What is it really being constrained? The element T, or the array
> > containing elements of T?
>
> We're constraining the array, because we want to be able to get begin
> and end iterators for any array.
Honesty, I didn't initially realize you tried to express a concept
definition in "member notation" for type T[N], and your proposal about
free function overloading is the smartest way to handle it.

I think the problem trying to operate on scalar types with "member
notation" would require C++ provided both object and operation notation
for POD types, like other vendor languages such as Java and C# do. But
this would make scalar types into something they aren't, in the sense
that such types have no unordered attributes (member functions and
types), only ordered (data storage).

In fact I think overloading resolution works perfectly well (perhaps
better).

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Thu, 11 Jan 2007 10:50:55 CST
Raw View
Douglas Gregor skrev:

> perrog@gmail.com wrote:
> > Such a hypothetical class concept would be some sort of protocol or
> > class outline, that 1) is empty in that it has no type-name; 2)
> > contains only non-data members and 3) a constrained template must be a
> > class-type. The name of the concept would represent the protocol, and
> > not a type-name.
>
> What benefits would this kind of "protocol" have over a concept?
0) To start with, I wasn't really trying to give rice and rose. :-)

1) Then, it would allow constraining templates to scalar (~POD) or
class types. Or maybe this should be an illegal constraint?

2) Std::allocator have not yet a concept specification. Is it because
there haven't been time to specify it, or because std::allocator don't
fits very well in a concept[*]?

3) Protocols is not more revolutionising than just abbreviating the set
of member requirements protocol[**], and the set of scalar requirements
concept. The main difference would supposedly be how concept_maps
instantiate the concept (and perhaps adding class into the concept
definition.)

4) The case when concepts helps compiler generating internal glue code
(such as for the for() and possible switch()?) is another fantastic
side of concepts. I even think this mechanism become more powerful if
scalar and class types would be separable via axioms,

5) Another point that requires massive text explanation.

[*]: The C++ library crypto++ make even more use of class template
parameters than STL does, http://www.cryptopp.com/.

[**]: Some C++ experts term member constraints policies.

>
> > >
> > > One problem with the code above is that the syntax can get rather
> > > clunky. What if we want to constrain T[N]?
> > >
> > >   template<typename T, std::size_t N>
> > >   concept_map Constraint<T[N]> {
> > >     iterator T[N]::begin() { return this; }
> > >     iterator T[N]::end() { return this + N; }
> > >   };
> > >
> > > Or maybe that should be:
> > >
> > >   template<typename T, std::size_t N>
> > >   concept_map Constraint<T[N]> {
> > >     iterator T::begin()[N] { return this; }
> > >     iterator T::end()[N] { return this + N; }
> > >   };
> > >
> > > ?
> > >
> > > C++'s declarator syntax is really scary as-is; extending it to deal
> > > with non-trivial nested name specifiers like the array type T[N] might
> > > be more trouble than its worth. We're already told to "prefer free
> > > functions to member functions"... perhaps the same should be true of
> > > concepts?
> >
> > What is it really being constrained? The element T, or the array
> > containing elements of T?
>
> We're constraining the array, because we want to be able to get begin
> and end iterators for any array.
Honesty, I didn't initially realize you tried to express a concept
definition in "member notation" for type T[N], and your proposal about
free function overloading is the smartest way to handle it.

I think the problem trying to operate on scalar types with "member
notation" would require C++ provided both object and operation notation
for POD types, like other vendor languages such as Java and C# do. But
this would make scalar types into something they aren't, in the sense
that such types have no unordered attributes (member functions and
types), only ordered (data storage).

In fact I think overloading resolution works perfectly well (perhaps
better).

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Tue, 2 Jan 2007 11:46:56 CST
Raw View
wkaras@yahoo.com wrote:
> Does all the new syntax give us clearer instantiation error
> messages?  If so, discussion of that fact would help build
> support.

Concepts eliminate instantiation-time errors almost entirely. You will
either get an error at template definition time (before instantiation
time) or you get an error in the use of the template (it will not be
instantiated). For example, if one were to write "max" like this:

  template<typename T>
  where LessThanComparable<T>
  const T& max(const T& x, const T& y) {
    return x > y? x : y;
  }

LessThanComparable only provides "<", so the compiler would produce an
error stating that there is no ">" operation for two values of type
"T". Note that we haven't instantiated "max" yet; we're checking the
uninstantiated template definition. For reference, ConceptGCC says:

  honk.cpp: In function 'const T& max(const T&, const T&)':
  honk.cpp:6: error: no match for 'operator>' in 'x > y'

Similarly, when we try to call (a corrected) max with a type that does
not provide a suitable "<" operator, the compiler will produce an error
says that the requirements of "max" are not met. It will not try to
instantiate "max", because the instantiation might fail. Again, here's
the ConceptGCC error message (I've invented the type 'X'):

  honk.cpp: In function 'int main()':
  honk.cpp:13: error: no matching function for call to 'max(X&,
X&)'
  honk.cpp:5: note: candidates are: const T& max(const T&, const T&)
[with T = X] <where clause>
  honk.cpp:13: note:   no concept map for requirement
'std::LessThanComparable<X, X>'

While concepts do improve template error messages, they also improve
the template system in many other ways. The papers and proposals
describe all of the various features of concepts, but the ones that
stand out---aside from separate type checking for templates---are
concept-based overloading, which allows you to overload based on, e.g.,
RandomAccessIterator vs. BidirectionalIterator, and syntax remapping
via concept maps, which allows you to adapt the syntax of a type to
meet the expectations of a template without changing either one.

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Wed, 3 Jan 2007 15:31:45 GMT
Raw View
Douglas Gregor wrote:
> Thorsten Ottosen wrote:
>
>>Douglas Gregor wrote:
>>This is ok for arguments that are read-only. But what if I have a
>>function that has these two overloads:
>>
>>auto concept Foo<class T>
>>{
>>   void foo(T);
>>};
>>

template< class T >
>>struct Bar
>>{
>>   void foo( const T& );
>>   void foo( T&& );
>>};
>>
>>How will the concept forward to the rigth one s.t. efficiency is
>>preserved? Will there be generated two functions?
>
>
> You'll get the first Bar::foo, always. If your "Foo" concept allows one
> to have different behavior based on an lvalue vs. an rvalue argument,
> put both "foo" functions into the concept definition, e.g.,
>
>   auto concept Foo<class T>
>   {
>     void foo(T); // same as void foo(const T&);
>     void foo(T&&);
>   }

Ok. I was thinking that perhaps the generated signature would be as follows:

template< class T >
void Foo<Bar<T>>::foo( T&& r )
{
   Bar::foo( std::forward(r) );
}

or something along those lines. The call to std::forward() being the
important thing.

-Thorsten

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: wkaras@yahoo.com
Date: Thu, 4 Jan 2007 11:20:40 CST
Raw View
Douglas Gregor wrote:
.
> concept-based overloading, which allows you to overload based on, e.g.,
> RandomAccessIterator vs. BidirectionalIterator
.

RandomAccessIterator would also (presumably) be a
BidirectionalIterator. Suppose I'm writing a RandomAccessIterator,
but I forget some obscure required member of
RandomAccessIterator (but not a member of BidirectionalIterator).
Would the compiler quietly use the
BidirectionalIterator overload of the template, leaving me to wonder
why my application is running slower than I expected?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Thu, 4 Jan 2007 14:52:55 CST
Raw View
wkaras@yahoo.com wrote:
> Douglas Gregor wrote:
> .
> > concept-based overloading, which allows you to overload based on, e.g.,
> > RandomAccessIterator vs. BidirectionalIterator
> .
>
> RandomAccessIterator would also (presumably) be a
> BidirectionalIterator.

Yes, absolutely. In concept-speak, the RandomAccessIterator concept is
a "refinement" of the BidirectionalIterator concept.

> Suppose I'm writing a RandomAccessIterator,
> but I forget some obscure required member of
> RandomAccessIterator (but not a member of BidirectionalIterator).
> Would the compiler quietly use the
> BidirectionalIterator overload of the template, leaving me to wonder
> why my application is running slower than I expected?

Overload resolution would not complain, because it has unambiguously
found a function that matches.

However, in the scenario you describe, the compiler will not stay
silent. To tell the compiler what kind of iterator your type is (input,
forward, mutable bidirectional, etc.), you will need to write a concept
map, e.g.,

  concept_map MutableRandomAccessIterator<my_iterator_type> { }

Since you've now claimed that your type is a mutable random access
iterator, the compiler will check that your type meets all of the
syntactic requirements stated by that concept... and emit an error if
you forgot to implement some obscure requirement (like operator[]).

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Thu, 4 Jan 2007 16:38:18 CST
Raw View
Douglas Gregor skrev:

> perrog@gmail.com wrote:
> > wkaras@yahoo.com skrev:
> > > With this approach, whether there's a default definition or not can
> > > be decided independently for each concept member function.
>
> The behavior described above is handled by "concept maps" in the
> concepts proposal. Anyway...
>
> > I could somewhat agree. It feels like concepts are some kind of
> > extroverted disposition of class norms, implemented via a class-like
> > phenomenon (the concept-body) that wraps the original class. Thus,
> > pointer to member functions, "concept pointers", and "array of
> > concept elements" becomes orthogonal types to its real types.
> >
> > But what if some concepts were "introverted", i.e. members of the
> > concepts are members of the class...? How could this be combined with
> > concepts?
>
> First of all, one can write signatures inside concepts that require
> certain member functions; aside from the syntax, concepts don't really
> distinguish between member functions and free functions. For instance,
> if we want to require member functions "begin" and "end" in our
> container concept, we can just write:
>
>   concept Container<typename X> {
>     InputIterator iterator = X::iterator;
>
>     iterator X::begin();
>     iterator X::end();
>   }
>
> vector<int> would meet the requirements of the concept, as would
> list<int>, map<string, int>, etc.

I'm afraid I didn't got the picture clear even after this hint. Should
this notation be matched with a concept_map free function syntax taking
the type as first parameter? Or will this act as a "formal" constraint
on types (such as STL vector, list, map, etc.) that already implements
begin() and end()? In constrast to other types, that may use
concept_maps to provide an implicit (default) definition and, hence,
becomes more "informal" constraints. Example:

  template<T> where Constrain<T> foo(T &t);

  typedef std::vector<int> A;

  struct B {
    typedef char *iterator;
    char *data;
    int length;
  };

  A a;
  B b;
  foo(a); // ok
  foo(b); // error

  concept_map Constrain<B> {
    iterator begin(B &b) { return b.data; }
    iterator end(B &b) { return b.data+b.length; }
  };

  foo(b); // now ok

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Thu, 4 Jan 2007 17:28:43 CST
Raw View
I've read the proposal about concept and have a question on how the
constrained template use the requirements as declarations. Consider the
following text from the paper on Concepts (N2042 page 16):

  First, when a constrained template is defined, the requirements
  of the concept act as declarations, ensuring that the template
  body is fully type-checked. Second, when a constrained template
  is used, the template arguments provided to the template must
  meet the requirements of the concept.

Where will the constraint checking really be performed? At the point
where the template is instantiated, or at the point where the type is
defined?

The reason I ask is because the paragraph is somewhat contradiction. It
feels like the first statement allows concepts to be use as a forward
declaration (or prototyping) mechanism to individual members, but the
next statement prohibits this.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Fri, 5 Jan 2007 09:45:34 CST
Raw View
perrog@gmail.com wrote:
> Douglas Gregor skrev:
> >   concept Container<typename X> {
> >     InputIterator iterator = X::iterator;
> >
> >     iterator X::begin();
> >     iterator X::end();
> >   }
> >
> > vector<int> would meet the requirements of the concept, as would
> > list<int>, map<string, int>, etc.
>
> I'm afraid I didn't got the picture clear even after this hint. Should
> this notation be matched with a concept_map free function syntax taking
> the type as first parameter?

No, it would not match a free function in the concept map.

> Or will this act as a "formal" constraint
> on types (such as STL vector, list, map, etc.) that already implements
> begin() and end()?

I think the answer is "yes", but I want to make sure I understand your
formal/informal distinction. Let's look at your example...

> In constrast to other types, that may use
> concept_maps to provide an implicit (default) definition and, hence,
> becomes more "informal" constraints.
> Example:
>
>   template<T> where Constrain<T> foo(T &t);
>
>   typedef std::vector<int> A;
>
>   struct B {
>     typedef char *iterator;
>     char *data;
>     int length;
>   };
>
>   A a;
>   B b;
>   foo(a); // ok

Yes, assuming "Constrain" is an "auto" concept. If it is not "auto",
would need need to add

  concept_map Constraint<A> { }

>   foo(b); // error
>
>   concept_map Constrain<B> {
>     iterator begin(B &b) { return b.data; }
>     iterator end(B &b) { return b.data+b.length; }
>   };
>
>   foo(b); // now ok

In this concept map, the free "begin" function would not match the
requirement for a member function "begin". One could conceivably write:

  concept_map Constrain<B> {
    iterator B::begin() { return b.data; }
    iterator B::end() { return b.data + b.length; }
  };

At present, this code is ill-formed (one cannot provide an
implementation for a member function in a concept map), but that
decision isn't necessarily final. I think this corresponds to your
"formal" constraint?

One problem with the code above is that the syntax can get rather
clunky. What if we want to constrain T[N]?

  template<typename T, std::size_t N>
  concept_map Constraint<T[N]> {
    iterator T[N]::begin() { return this; }
    iterator T[N]::end() { return this + N; }
  };

Or maybe that should be:

  template<typename T, std::size_t N>
  concept_map Constraint<T[N]> {
    iterator T::begin()[N] { return this; }
    iterator T::end()[N] { return this + N; }
  };

?

C++'s declarator syntax is really scary as-is; extending it to deal
with non-trivial nested name specifiers like the array type T[N] might
be more trouble than its worth. We're already told to "prefer free
functions to member functions"... perhaps the same should be true of
concepts?

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Fri, 5 Jan 2007 09:46:21 CST
Raw View
perrog@gmail.com wrote:
> I've read the proposal about concept and have a question on how the
> constrained template use the requirements as declarations. Consider the
> following text from the paper on Concepts (N2042 page 16):
>
>   First, when a constrained template is defined, the requirements
>   of the concept act as declarations, ensuring that the template
>   body is fully type-checked. Second, when a constrained template
>   is used, the template arguments provided to the template must
>   meet the requirements of the concept.
>
> Where will the constraint checking really be performed? At the point
> where the template is instantiated, or at the point where the type is
> defined?

That excerpt is describing the two roles that concepts play in
type-checking for templates. Concepts play the first role (where the
requirements act as declarations) when we're type-checking the
definition of a constrained template. At this time, there is no
instantiation; just the template itself. For example, let's take a look
at min():

  template<LessThanComparable T>
  const T& min(const T& x, const T& y) {
    return x < y? x : y;
  }

When type-checking "min", the compiler needs "<" to match some existing
operator<. The only such operator is the requirement for "operator<" in
LessThanComparable<T>, which is acting as a declaration. The compiler
will find this operator<, note that it takes two T's (good) and returns
a bool (so it can be used for the ? : operator), so the type-check
succeeds.

Concepts play the second role, where we need to verify that a type or
set of types meets the requirements of the concept, when we're trying
to call min. Example:

  auto concept LessThanComparable<typename T> {
    bool operator<(T, T);
  }

  struct X { bool before(const X&) const; };

  min(17, 42); // okay: implicit matching with "auto" works for
integers

  X x, y;
  min(x, y); // error: no operator<(X, X), so implicit matching fails
and X is not LessThanComparable

  concept_map LessThanComparable<X> {
    bool operator<(X x, X y) { return x.before(y); }
  }; // okay: concept map satisfies all of the requirements of
LessThanComparable for X

  min(x, y); // okay: we use LessThanComparable<X> concept map to meet
min's requirements

Concepts play two different roles, but they are two sides of the same
coin. You can think of concepts like a legal contract: both sides of
the deal have to satisfy the requirements of the contract, or the
contract doesn't work. In the min() example, one side of the contract
is min() itself, which can only rely on T to have the behaviors set
forth in the concept LessThanComparable, and the other side of the
contract is X, which must provide all of the behaviors set form in the
concept LessThanComparable.

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: Fri, 5 Jan 2007 10:26:50 CST
Raw View
Thorsten Ottosen wrote:
> Douglas Gregor wrote:
>
>> Thorsten Ottosen wrote:

> Ok. I was thinking that perhaps the generated signature would be as
> follows:

Let me try to give a better example of the forwarding capabilities of
concepts.

Consider a container concept

auto concept container<typename T>
{
   typename  value_type;
   void T::push_back( value_type );
};

This could generate the following concept_map for a container X:

template< class T >
where convetible<T,X::value_type>
void container<X>::push_back( T&& r )
{
  X::push_back( std::forward(r) );
}

This way

- the most efficient function in X is always called
- the concept does not have to worry about perfect forwarding (which
would be an even bigger problem for multiple arguments)

IOW, the concept function arguments do, by default, *never* interfere
with lvalue/rvalue/constness properties of the actual arguments.

problems:

- std::forward is a library function

Apologies if I have completely misunderstood how it all works.

-Thorsten


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Sat, 6 Jan 2007 11:47:01 CST
Raw View
Douglas Gregor skrev:

> > Or will this act as a "formal" constraint
> > on types (such as STL vector, list, map, etc.) that already implements
> > begin() and end()?
>
> I think the answer is "yes", but I want to make sure I understand your
> formal/informal distinction. Let's look at your example...
>
> > In constrast to other types, that may use
> > concept_maps to provide an implicit (default) definition and, hence,
> > becomes more "informal" constraints.
> > Example:
> >
> >   template<T> where Constrain<T> foo(T &t);
> >
> >   typedef std::vector<int> A;
> >
> >   struct B {
> >     typedef char *iterator;
> >     char *data;
> >     int length;
> >   };
> >
> >   A a;
> >   B b;
> >   foo(a); // ok
>
> Yes, assuming "Constrain" is an "auto" concept. If it is not "auto",
> would need need to add
>
>   concept_map Constraint<A> { }
>
> >   foo(b); // error
> >
> >   concept_map Constrain<B> {
> >     iterator begin(B &b) { return b.data; }
> >     iterator end(B &b) { return b.data+b.length; }
> >   };
> >
> >   foo(b); // now ok
>
> In this concept map, the free "begin" function would not match the
> requirement for a member function "begin". One could conceivably write:
>
>   concept_map Constrain<B> {
>     iterator B::begin() { return b.data; }
>     iterator B::end() { return b.data + b.length; }
>   };
>
> At present, this code is ill-formed (one cannot provide an
> implementation for a member function in a concept map), but that
> decision isn't necessarily final. I think this corresponds to your
> "formal" constraint?

Right, and sorry for the inconvenience with my alien terms. I recently
found an earlier paper on concepts [N1758,
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1758.pdf]
where this separation is discussed in more detail, but in terms of
concepts and models/concept_maps.

Concepts have large potential such as constructing class member
constraints and thus not only being operator constraints. In a way,
member constraints would also work (via concept_maps) like a protocol
or taxonomy of a class, i.e ensuring a class type is implemented in
terms of its protocol.

Anyway, it feels like the concept proposal, if not limited at least
focusing on free function constraints. Luckily, most built-in operators
has an alternative free function syntax, that practically can be
considered as an internal (compile-parser) way of adding new members to
classes. Hence, many operators need not be member functions. Thus, it
would unlikely become a conflict if class member constraints used a
slightly different definition, like a class definition, instead of
plain concept definitions.

But the variants shouldn't be more different than a class concept may
adopt constraints from plain concepts. A class concept would be more
expressive for member constraints. Still, such concepts would not be
types.

Such a hypothetical class concept would be some sort of protocol or
class outline, that 1) is empty in that it has no type-name; 2)
contains only non-data members and 3) a constrained template must be a
class-type. The name of the concept would represent the protocol, and
not a type-name.

>
> One problem with the code above is that the syntax can get rather
> clunky. What if we want to constrain T[N]?
>
>   template<typename T, std::size_t N>
>   concept_map Constraint<T[N]> {
>     iterator T[N]::begin() { return this; }
>     iterator T[N]::end() { return this + N; }
>   };
>
> Or maybe that should be:
>
>   template<typename T, std::size_t N>
>   concept_map Constraint<T[N]> {
>     iterator T::begin()[N] { return this; }
>     iterator T::end()[N] { return this + N; }
>   };
>
> ?
>
> C++'s declarator syntax is really scary as-is; extending it to deal
> with non-trivial nested name specifiers like the array type T[N] might
> be more trouble than its worth. We're already told to "prefer free
> functions to member functions"... perhaps the same should be true of
> concepts?

What is it really being constrained? The element T, or the array
containing elements of T?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "perrog@gmail.com" <perrog@gmail.com>
Date: Tue, 26 Dec 2006 17:23:05 CST
Raw View
wkaras@yahoo.com skrev:

>
> OK, let me throw this beer bottle from here in the bleachers:
>
> Seems like LessThanComparable could itself be just a template.  Doesn't
> really save me that much work to have a separate syntax for "concepts".
>
>    template<typename T>
>    using LessThanComparable<T> // substitution failure IS an error.
>    const T& min(const T& x, const T& y) {
>      return x < y? x : y;  }
>
> template <typename T>
> struct LessThanComparable
> {
> // This would have to be made legal, including for
> // T of built-in type.  "explicit" means declaration is
> // not visible within class without LessThanComparable::
> // prefix.
> explicit static bool operator < (const T&x, const T&y)
>     { return(x < y); }
> };
>
> With this approach, whether there's a default definition or not can
> be decided independently for each concept member function.

I could somewhat agree. It feels like concepts are some kind of
extroverted disposition of class norms, implemented via a class-like
phenomenon (the concept-body) that wraps the original class. Thus,
pointer to member functions, "concept pointers", and "array of
concept elements" becomes orthogonal types to its real types.

But what if some concepts were "introverted", i.e. members of the
concepts are members of the class...? How could this be combined with
concepts?

Unfortunately, pointer and reference to concepts are excluded in
current proposal. Albeit, there are a few "concept pointers"
already today. For example, "int *" points to a type that
implements certain kinds of operators. Basically, if pointer to
concepts should be prohibited, it feels like we need to prohibit
pointer to POD-types in C++.

Merry Christmus in late,
Roger

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Tue, 2 Jan 2007 09:00:00 CST
Raw View
Thorsten Ottosen wrote:
> Douglas Gregor wrote:
> This is ok for arguments that are read-only. But what if I have a
> function that has these two overloads:
>
> auto concept Foo<class T>
> {
>    void foo(T);
> };
>
> struct Bar
> {
>    void foo( const T& );
>    void foo( T&& );
> };
>
> How will the concept forward to the rigth one s.t. efficiency is
> preserved? Will there be generated two functions?

You'll get the first Bar::foo, always. If your "Foo" concept allows one
to have different behavior based on an lvalue vs. an rvalue argument,
put both "foo" functions into the concept definition, e.g.,

  auto concept Foo<class T>
  {
    void foo(T); // same as void foo(const T&);
    void foo(T&&);
  }

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Tue, 2 Jan 2007 09:00:42 CST
Raw View
perrog@gmail.com wrote:
> wkaras@yahoo.com skrev:
> > With this approach, whether there's a default definition or not can
> > be decided independently for each concept member function.

The behavior described above is handled by "concept maps" in the
concepts proposal. Anyway...

> I could somewhat agree. It feels like concepts are some kind of
> extroverted disposition of class norms, implemented via a class-like
> phenomenon (the concept-body) that wraps the original class. Thus,
> pointer to member functions, "concept pointers", and "array of
> concept elements" becomes orthogonal types to its real types.
>
> But what if some concepts were "introverted", i.e. members of the
> concepts are members of the class...? How could this be combined with
> concepts?

First of all, one can write signatures inside concepts that require
certain member functions; aside from the syntax, concepts don't really
distinguish between member functions and free functions. For instance,
if we want to require member functions "begin" and "end" in our
container concept, we can just write:

  concept Container<typename X> {
    InputIterator iterator = X::iterator;

    iterator X::begin();
    iterator X::end();
  }

vector<int> would meet the requirements of the concept, as would
list<int>, map<string, int>, etc.

If concepts were to map members of the concepts members of the class,
we'd run into a bit of a problem with multi-parameter concepts, e.g.,

  auto concept EqualityComparable<typename T, typename U> {
    bool operator<(T, U);
  }

Which class is operator< a part of, T or U? What if neither T nor U is
a class?

> Unfortunately, pointer and reference to concepts are excluded in
> current proposal.

Many of us (myself included) come from an object-oriented background,
and because of this one of the hardest things to grasp with concepts is
that concepts are not types. In the OO world, when we want to model an
animal, we write an Animal abstract base class and write specific kinds
of animals (say, Beaver) as subclasses of Animal. So Animal acts as
both a way to describe the requirements on animals (because its members
are common to all animals) and as a way to manipulate any kind of
animal without knowing which one ("Animal*" can point to any subclass
of Animal, i.e., any kind of animal).

Concepts work differently, because they only describe the requirements
on types. So, a concept 'Animal' says what all animals do (in its
members), and anything that behaves like an animal will have a "concept
map" stating how it meets the requirements of the Animal concept. If
you want to manipulate any kind of animal without knowing what specific
kind of animal you have, create a template parameter 'A' and state that
it meets the requirements of the 'Animal' concept. So, concepts
separate the mechanism of describing the properties and behavior of
types (concepts) from the mechanism for writing generic
functions/classes that can act on any type that meets those properties
(templates).

Concepts support a truly different paradigm---we call it "generic
programming"---than the existing mechanisms for object-oriented
programming.

  Cheers,
  Doug

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Thu, 21 Dec 2006 10:53:02 CST
Raw View
Scott Meyers wrote:
> Consider the following text from the June 24, 2006, paper on Concepts
> (N2042 --
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2042.pdf):
>
>    Here is the definition of LessThanComparable:
>
>    auto concept LessThanComparable<typename T> {
>      bool operator<(T, T);
>    };
>
>    [...]
>    Inside the body of the concept, we list the declarations that we
>    expect to have, i.e., an operator< that takes two T parameters and
>    returns a bool.
>
> Is this really what the above specifies?  I'd expect it to mean that
> that there must be a function named operator< that can be called with
> two objects of type T and that returns a type implicitly convertable
> to bool, i.e., that given objects t1 and t2 of type T, the following
> expression is legal:
>
>    bool b(t1<t1);
>
> Is my expectation correct, or do concepts really specify specific
> function signatures?

Yes.

To both.

The LessThanComparable concept really specifies that there is a
function with the signature "bool operator<(T, T)". That's the
declaration we see when we're inside a constrained template like min:

  template<typename T>
  where LessThanComparable<T>
  const T& min(const T& x, const T& y) {
    return x < y? x : y; // x < y finds
LessThanComparable<T>::operator<
  }

Your explanation is also correct: for a given type X to be
LessThanComparable, one needs an operator< whose parameters can be
initialized with values of type X and whose result type is convertible
to bool.

However, the operator< in LessThanComparable and the operator< for your
type X aren't the same function. LessThanComparable for X has its own
operator<, which will be implicitly generated with the following
definition:

  bool LessThanComparable<X>::operator<(const X& x1, const X& x2) {
    return x1 < x2;
  }

So LessThanComparable's operator< has exactly the signature we said it
did [*], but the actual < it binds to in its definition has the looser
requirements you described, e.g., it could be:

  struct Y { Y(const X&); };
  int operator<(Y, Y);

The definition of LessThanComparable<X>::operator< will find this "int
operator<(Y, Y)" and bind to it.

LessThanComparable<X>::operator< is actually part of the "concept map"
LessThanComparable<X>. Concept maps state how a given set of types
(here, the type "X") meet the requirements of a concept. In this case,
the concept map LessThanComparable<X> and its operator< are implicitly
generated by the compiler.

With "auto" concepts like LessThanComparable, the compiler will
implicitly define concept maps when we need them. However, we're always
free to define our own concept map, which can either use
implicitly-generated members like operator<

  concept_map LessThanComparable<X> { }; // operator< is implicitly
generated, as above

or can specify implementations of members:

  concept_map LessThanComparable<X> {
    bool operator<(X x1, X x2) {
      return x1.equals(x2);
    }
  };

  Cheers,
  Doug

[*] The "const &" is implicitly added to eliminate unwanted copies when
passing parameters into signatures.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: usenet@aristeia.com (Scott Meyers)
Date: Fri, 22 Dec 2006 05:53:31 GMT
Raw View
Douglas Gregor wrote:
> Yes.
>
> To both.

Oh, this is going to be fun to explain to people....

Thanks for the explanation, which, upon third reading, actually began to
make sense :-)

Scott

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Anders Dalvander" <google@dalvander.com>
Date: Fri, 22 Dec 2006 17:39:41 CST
Raw View
Douglas Gregor wrote:
> [*] The "const &" is implicitly added to eliminate unwanted copies when
> passing parameters into signatures.

Shouldn't a rvalue reference be used instead of a lvalue reference?

// Anders Dalvander

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: wkaras@yahoo.com
Date: Fri, 22 Dec 2006 17:47:15 CST
Raw View
Douglas Gregor wrote:
> Scott Meyers wrote:
> > Consider the following text from the June 24, 2006, paper on Concepts
> > (N2042 --
> > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2042.pdf):
> >
> >    Here is the definition of LessThanComparable:
> >
> >    auto concept LessThanComparable<typename T> {
> >      bool operator<(T, T);
> >    };
> >
> >    [...]
> >    Inside the body of the concept, we list the declarations that we
> >    expect to have, i.e., an operator< that takes two T parameters and
> >    returns a bool.
> >
> > Is this really what the above specifies?  I'd expect it to mean that
> > that there must be a function named operator< that can be called with
> > two objects of type T and that returns a type implicitly convertable
> > to bool, i.e., that given objects t1 and t2 of type T, the following
> > expression is legal:
> >
> >    bool b(t1<t1);
> >
> > Is my expectation correct, or do concepts really specify specific
> > function signatures?
>
> Yes.
>
> To both.
>
> The LessThanComparable concept really specifies that there is a
> function with the signature "bool operator<(T, T)". That's the
> declaration we see when we're inside a constrained template like min:
>
>   template<typename T>
>   where LessThanComparable<T>
>   const T& min(const T& x, const T& y) {
>     return x < y? x : y; // x < y finds
> LessThanComparable<T>::operator<
>   }
>
> Your explanation is also correct: for a given type X to be
> LessThanComparable, one needs an operator< whose parameters can be
> initialized with values of type X and whose result type is convertible
> to bool.
>
> However, the operator< in LessThanComparable and the operator< for your
> type X aren't the same function. LessThanComparable for X has its own
> operator<, which will be implicitly generated with the following
> definition:
>
>   bool LessThanComparable<X>::operator<(const X& x1, const X& x2) {
>     return x1 < x2;
>   }
.

OK, let me throw this beer bottle from here in the bleachers:

Seems like LessThanComparable could itself be just a template.  Doesn't
really save me that much work to have a separate syntax for "concepts".

   template<typename T>
   using LessThanComparable<T> // substitution failure IS an error.
   const T& min(const T& x, const T& y) {
     return x < y? x : y;  }

template <typename T>
struct LessThanComparable
{
// This would have to be made legal, including for
// T of built-in type.  "explicit" means declaration is
// not visible within class without LessThanComparable::
// prefix.
explicit static bool operator < (const T&x, const T&y)
    { return(x < y); }
};

With this approach, whether there's a default definition or not can
be decided independently for each concept member function.

Does all the new syntax give us clearer instantiation error
messages?  If so, discussion of that fact would help build
support.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Sat, 23 Dec 2006 21:10:36 GMT
Raw View
usenet@aristeia.com (Scott Meyers) writes:

> Douglas Gregor wrote:
>> Yes.
>>
>> To both.
>
> Oh, this is going to be fun to explain to people....
>
> Thanks for the explanation, which, upon third reading, actually began
> to make sense :-)

Hi Scott,

Once you've explained how boost/tr1::function works, the signatures of
concepts also make a lot of sense.  And vice-versa.  If the analogy
isn't immediately obvious to you, just ask :)

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: Sun, 24 Dec 2006 12:25:16 CST
Raw View
Douglas Gregor wrote:
> Scott Meyers wrote:
>
>>Consider the following text from the June 24, 2006, paper on Concepts
>>(N2042 --
>>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2042.pdf):
>>
>>   Here is the definition of LessThanComparable:
>>
>>   auto concept LessThanComparable<typename T> {
>>     bool operator<(T, T);
>>   };
>>

> However, the operator< in LessThanComparable and the operator< for your
> type X aren't the same function. LessThanComparable for X has its own
> operator<, which will be implicitly generated with the following
> definition:
>
>   bool LessThanComparable<X>::operator<(const X& x1, const X& x2) {
>     return x1 < x2;
>   }

This is ok for arguments that are read-only. But what if I have a
function that has these two overloads:

auto concept Foo<class T>
{
   void foo(T);
};

struct Bar
{
   void foo( const T& );
   void foo( T&& );
};

How will the concept forward to the rigth one s.t. efficiency is
preserved? Will there be generated two functions?

-Thorsten

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: usenet@aristeia.com (Scott Meyers)
Date: Thu, 21 Dec 2006 06:36:52 GMT
Raw View
I understand the general idea behind concepts, but I'm not clear on
the details of how they are likely to be integrated into C++0x.
Consider the following text from the June 24, 2006, paper on Concepts
(N2042 --
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2042.pdf):

   Here is the definition of LessThanComparable:

   auto concept LessThanComparable<typename T> {
     bool operator<(T, T);
   };

   [...]
   Inside the body of the concept, we list the declarations that we
   expect to have, i.e., an operator< that takes two T parameters and
   returns a bool.

Is this really what the above specifies?  I'd expect it to mean that
that there must be a function named operator< that can be called with
two objects of type T and that returns a type implicitly convertable
to bool, i.e., that given objects t1 and t2 of type T, the following
expression is legal:

   bool b(t1<t1);

Is my expectation correct, or do concepts really specify specific
function signatures?

Thanks,

Scott

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]