I returned home yesterday from attending the ISO C++ 2016 standard committee meeting held in Jacksonville, Florida 02/29-03/05 and decided to share my observations regarding why the Concepts TS wasn’t adopted for C++17. This decision by the committee may come as a surprise to many who are eager for Concepts and have been expecting it to be included in C++17.

The short explanation is: the committee failed to achieve consensus that Concepts, as specified in the TS, has attained sufficient implementation and usage experience to be confident in the current design. Basically, the committee did not say “no” to concepts, it said “not yet.”

The long explanation is, well, longer…

The most significant opposition was not due to technical concerns. The primary concerns raised included:

The Concepts TS [Concepts] was published 2015-11-15 following approval by the committee in between the Lenexa and Kona meetings. The TS has therefore only existed in a published form for less than four months. The only known publicly available implementation is in an unreleased version of the gcc compiler. The implementation in the gcc compiler was developed by the same (very talented) individual that wrote the specification. An implementation is therefore available for testing, but no known attempt has been made to produce an implementation based on the specification and the specification is therefore untested. Several core working group (CWG) members indicated that having an implementation produced from specification is critical for identifying specification issues. The most significant known usage of Concepts is in the Ranges TS [Ranges] and in its only known implementation in Casey Carter and Eric Niebler’s cmcstl2 [cmcstl2]. There are a few other projects experimenting with Concepts (including my own text_view [Text_view] library), but none that approach the scale that would be expected when developers really start making use of the feature. Performance and error handling issues with the current gcc implementation provide further evidence that no such large scale attempts at using Concepts exists. The Concepts TS does not specify any concept definitions. Some committee members question the usefulness of concepts without the availability of a concept definition library such as that in the Ranges TS. Adopting the Concepts TS into C++17 without a corresponding concept definition library risks locking down the language without proof that it provides the features needed to implement a library as might be designed to conceptify the standard library.

If more implementation and usage experience had been available, would it have affected the decision to adopt Concepts into C++17? I’m not sure. A number of technical concerns were raised and I suspect that at least one nation body was prepared to vote no on a final C++17 publication if it included Concepts in its current form. Technical concerns raised throughout the week included:

The Concepts TS includes new syntax to define function templates. An abbreviated function template declaration looks similar to a non-template function declaration except that at least one of its parameters is declared with a placeholder type specifier; either ‘auto’ or the name of a concept. The concern is that a declaration like this:

void f(X x) {}

defines a non-template function if ‘X’ is a type, but defines a function template if ‘X’ is a concept. This has subtle ramifications for whether the function can be defined in a header file, whether the typename keyword is needed to reference member types of ‘X’, whether parameters declared with rvalue reference qualifiers are forwarding references or parameters that only bind to rvalue arguments, whether there is exactly one variable or potentially none or many for each declared static local variable, etc… The Concepts TS also includes a template-introduction syntax that allows omitting the verbose template declaration syntax that we’re all used to while simultaneously stating type constraints. For example, the following declares function template ‘f’ taking two parameters ‘A’ and ‘B’ that satisfy concept C:

C{A,B} void f(A a, B b);

This syntax is not loved by all. It was mentioned that a version of the Ranges TS used it at one point and the library evolution working group (LEWG) requested that it be changed and never used again. There are two forms of concept definitions; function and variable. The function form exists to support overloading of concept definitions based on template parameter arity. The variable form exists to support slightly shorter definitions.

// function form:

template<typename T>

concept bool C() {

return ...;

}



// variable form:

template<typename T>

concept bool C = ...;

All concepts that can be defined using the variable form can be defined using the function form. The form that is used impacts the syntax required to evaluate a concept, thus usage of a concept requires knowing the form used to define the concept. An early version of the Ranges TS used both the variable and function forms to define concepts and the inconsistency produced many errors in specification. The current Ranges TS uses only the function form to define specified concepts. Some committee members feel that a single concept definition form would simplify the language and avoid usage and teaching difficulties. Providing a distinct syntax for defining concepts rather than defining them in terms of functions or variables would also avoid the awkward ‘concept bool’ syntax. A revision of P0127R0 [P0127R0] was approved by the evolution working group (EWG) in Jacksonville for C++17. This proposal adds the ability to use ‘auto’ as a type specifier for a non-type template parameter:

template<auto V>

constexpr auto v = V*2;

With Concepts, one might want to constrain the above template such that the type of ‘V’ must satisfy the Integral concept:

template<Integral V>

constexpr auto v = V*2;

However, this is the same syntax currently used by the Concepts TS to declare a constrained template type parameter. If the Concepts TS were to be adopted, then some other syntax would be needed to declare a constrained non-type template parameter. Arguably, the syntax used by the Concepts TS would be more suitable for declaring template non-type parameters as shown above since this matches the syntax used for other variable declarations. This implies that a new syntax for declaring constrained type parameters would be desirable for language consistency reasons. Concepts have been widely expected to produce better error messages than are currently produced when template instantiation fails. The theory goes, since Concepts enables rejecting code based on a constraint at the point of usage of a template, the compiler can simply report the constraint failure rather than an error in some expression in a potentially deeply nested template instantiation stack. Unfortunately, it turns out not to be so simple and use of concepts sometimes results in worse error messages. Constraint failures frequently manifest as overload resolution failures resulting in a potentially long list of candidates, each with its own list of reasons for rejection. Identifying the candidate that was intended for a given use and then figuring out why the constraint failure occurred, can be a worse experience than navigating a template instantiation stack. A number of committee members are concerned about whether the current Concepts design suffices as a foundation on which full template definition checking can be implemented in the future. Though assertions were made by Concepts advocates that such checking will be possible, many questions remain unanswered, and these committee members remain unconvinced. It seems unlikely that these concerns will be addressed other than through an implementation of definition checking.

I’m confident that Concepts, in some form, will be added to C++19/20. I expect all of gcc, Clang, and Visual C++ to be shipping implementations well before the next standard is complete, hopefully within the next year. While we await the growth of confidence in the Concepts design, I hope to see changes made to address at least some of the technical concerns listed above as I think addressing these will help to build consensus and avoid surprises when we next consider adopting Concepts into the C++ standard.

In the next few posts, I’ll explore the technical design concerns above in more depth and discuss possible solutions.

References: