Document number: Date: Project: Reply-to: |
N2916=09-0106 2009-06-22 Programming Language C++, Core Working Group David Abrahams <dave at boostpro dot com> Beman Dawes <bdawes at acm dot org> |
A C++0x concept map can be useful (among other things) as:
As of CD1, concept maps used for this purpose are often empty:
class Endian { ... }; concept_map std::Regular<Endian> {} concept_map std::StandardLayoutType<Endian> {} concept_map std::TrivialType<Endian> {}
Although this formulation is technically sufficient and will ensure the type models the concepts, it has some problems:
This paper proposes that the above code could also be written as:
class Endian -> std::Regular, std::StandardLayoutType, std::TrivialType { ... };
The proposed wording uses ->
as a syntax marker
for the beginning of the list of concepts to be mapped. The authors
considered several alternate keyword and punctuation possibilities
and are not wedded to the use of ->
. We welcome
syntax suggestions from the committee (keeping in mind the usual
"bicycle shed" caveat, of course!)
We describe here our rationale for rejecting the use
of requires
as a marker only because we consider the
argument sufficiently subtle to be a potential time-waster for the
committee. The problem is that using requires
makes
a concept_map
look too much like a
requires
clause in a region of code where either one
could appear. A
concept_map
is fundamentally different from a
requires
clause. When you write:
you're just constraining X, nothing more. It's pure requirement checking. However, when you write:template <typename X> requires<EqualityComparable<X> > class Y { ... };
you're generating a concept map for all specializations oftemplate <typename X> class Y -> EqualityComparable { ... };
Y
, with all that that implies (e.g. generation of defaults,
Y<T> can be used where EqualityComparable is required, etc):
// generated by the above template <typename T> concept_map EqualityComparable<Y<T> > { };
The critical motivation for this proposal is the desire to be able to say "my type models concepts XXX, YYY, and ZZZ, and please tell me if I get it wrong (structurally)", and to do that in such a way that users and maintainers understand that this is part of my type's public interface and not just happenstance.
This proposal is not replacement for concept maps; we view
concept maps—even empty ones—as meeting critical
needs. We wish to make empty concept maps more convenient, more
expressive, and less verbose in the common case where one is
intentionally creating a model of a known concept. Empty
concept_map
s will still be needed in their current form
for nonintrusive post-hoc adaptation of types to concepts, an important function
of concept_map
s in general.
Another important motivation for this proposal is that it provides a powerful platform for the common case of exported concept maps as proposed by N2918=09-0108, with zero syntactic overhead.
Change 9 Classes [class] as indicated:
A class is a type. Its name becomes a class-name (9.1) within its scope.
class-name:
identifier
simple-template-idClass-specifiers and elaborated-type-specifiers (7.1.6.3) are used to make class-names. An object of a class consists of a (possibly empty) sequence of members and base class objects.
class-specifier:
class-head{
member-specificationopt}
class-head:
class-key identifieropt attribute-specifieropt mapped-concept-clauseopt base-clauseopt
class-key nested-name-specifier identifier attribute-specifieropt mapped-concept-clauseopt base-clauseopt
class-key nested-name-specifieropt simple-template-id attribute-specifieropt mapped-concept-clauseopt base-clauseoptclass-key:
class
struct
union
After 9.9 Nested type names [class.nested.type], add:
9.10 Intentional concept mapping [class.concept.mapping]
mapped-concept-clause:
->
mapped-concept-listmapped-concept-list:
mapped-concept,
mapped-concept-list
mapped-conceptmapped-concept:
::
opt nested-name-specifieropt concept-nameA mapped-concept-clause contains a list of concepts to map to. A concept is "mapped to" for each mapped-concept as if by a
concept_map
([concept.map]). Theconcept_map
acts as if it appears immediately after the class being defined, and is equivalent to:concept_map Concept<Class> {};where
Concept
is the mapped-concept, andClass
is the class where the mapped-concept-clause appears.[Example:
template <typename X> class Y -> EqualityComparable { ... };The above implicitly generates the following concept map:
template <typename T> concept_map EqualityComparable< Y<T> > {};--end example]
Several people on the committee reflectors suggested features similar to
this proposal, often with syntax using the requires
keyword.
Jerry Schwarz, in committee message c++std-lib-23459, suggested syntax that
mimics inheritance.