
C++ concepts support merged into GCC trunk - octoploid
https://gcc.gnu.org/ml/gcc-patches/2015-08/msg00377.html
======
cshimmin
For others like me who have been living under a rock:

[https://en.wikipedia.org/wiki/Concepts_(C%2B%2B)](https://en.wikipedia.org/wiki/Concepts_\(C%2B%2B\))

~~~
jokoon
So their primary function is to make template error messages more readable, by
giving tools to the programmer to be more specific when defining template
types?

I really need to see a comparison with examples that shows that it's
interesting to use, if I remember template metaprogramming was not an intended
use, so are concepts redirecting the language to saner places ?

It seems like it could be beneficial for certain specific software like math
software (maybe AI or language software ?), but other than that I feel very
unable to grasp concepts. Maybe a CS teacher could explain it better to me.
Again, can't wait for Effective C++ to cover those, but a slight introduction
would not hurt :)

~~~
maxlybbert
Concepts were supposed to be one of the big features of C++11. They weren't
going to make templates more efficient, but they would make working with
templates a little easier. Eventually, they became unwieldy, and they made
compilation times much worse. The Committee had the pressure to ship and fix
it later that Hoare talked about in his Turing Award lecture (
[http://www.cs.fsu.edu/~engelen/courses/COP4610/hoare.pdf](http://www.cs.fsu.edu/~engelen/courses/COP4610/hoare.pdf)
).

Surprisingly, they resisted Hoare's "mad dash" and deferred concepts. This
article is about a stripped-down version of concepts that was accepted into
the upcoming version of C++. It's supposed to have most of the benefits of the
C++11 proposal, without the complexity.

But I have to admit that the main benefits are better error messages, explicit
comments in code of what a template requires, and an additional syntax for
declaring/defining templates. The C++11 proposal was more exciting, but there
was a question of whether it went too far.

~~~
ArtB
Any summary on what was omitted? I'm not a C++ programmer so going to the
source wouldn't help me much, but I'd love to know.

~~~
maxlybbert
I hadn't followed the original proposal closely, so I can't give a complete
list. One feature I know about, that was implementable but very expensive, was
the ability to specify multiple ways that a type could match a concept. For
instance, a Sortable concept could mean the type has an operator<, _or_ could
be passed to the function compare(). I'm sure there was a way to handle cases
where a type had both. But then, if you had a type with a method, say
lessThan(), you could somehow specify that was an acceptable operator<, and
then use anything that relied on the Sortable concept. As far as I know, that
isn't in "concepts light."

------
qznc
After watching this talk [0] by Andrei Alexandrescu, I became somewhat
sceptical about concepts (and type classes and traits). Nevertheless, it's
probably an improvement for C++.

[0]
[https://www.youtube.com/watch?v=mCrVYYlFTrA](https://www.youtube.com/watch?v=mCrVYYlFTrA)

~~~
enqk
Can you summarize what you found convincing about his presentation?

The narrative of the presentation is him focusing on a case where they don't
work and tries to claim they _never_ work. His pretty brash conclusions do not
follow from his "demonstration"

~~~
qznc
I tried to document my insight here:
[http://beza1e1.tuxen.de/articles/interface_fail.html](http://beza1e1.tuxen.de/articles/interface_fail.html)

Concepts probably work for 80% of the cases and you can work around the rest
intuitively. On the other hand, we might not have realized how some algorithms
can be written even more generic with "static if".

~~~
enqk
Really cool of you to document your insights, I wish more people would do that
:)

~~~
qznc
Thanks. That is one of the essential elements of blogging for me. It allows me
to link to larger text from short comments. ;)

------
kirab
I'm really glad that concepts are finally making their way in after such a
long time. Concepts make using and developing templates so much more straight-
forward and easier to read!

~~~
pmr_
How do you know that? Have you had any practical experience with a large code
base using new style (e.g. post-C++11) Concepts? People have been using
Concepts in some form for a very long time and even properly documented they
can still be a major hurdle to less advanced or interested users.

------
smegel
So type checking for thing inside the <> as well as the ()?

~~~
repsilat
I think so.

I figure C++ has a static type system in most places because it helps the
language be fast -- resolving the target of a method call at compile time
turns it into a straight function call, and straight function calls can be
inlined etc etc. You know how big your objects might be, so you can put them
on the stack and you can copy them back and forth.

Templates give you a limited kind of polymorphism without sacrificing all of
this nice stuff. Compilation of templates is "interpreted", though -- you
don't compile a program to quickly instantiate them, you don't JIT them, the
data structure just keeps data structures in memory along with its ASTs and it
iterates over them, doing its type-checking and everything else "the slow
way". I guess C++ compilation looks a lot like Python interpretation, with "No
candidate for operator<(const T)&" standing in for AttributeError, and pages
of horrible template messages standing in for tracebacks.

This analogy raises a question, though -- if Python doesn't need type checking
to get nice error messages, why do C++ templates? An alternative to "assert
hasattr(a, '__cmp__')" is try-catch.

Why not do the same with std::sort? Put a big compile-time try-catch around
it, catch your template errors and present a nice message to your users.

What benefits would this have over type checking? If anyone wrote their
concept specifications too strictly, they might stop your valid program from
compiling, and this wouldn't happen with static try-catch. Maybe they thought
you needed a random access iterator when all you needed was a forward
iterator.

What benefits might concepts provide? Same as regular type checking -- if you
_know_ that the provided type has to present a given interface, you probably
do something crazy like give your compile-time types vtables for the
interface, and dramatically speed up compilation times. I don't know that
anyone will actually do anything like this, though.

~~~
KayEss
Most of what you propose already exists in the form of type traits together
with `static_assert`. Originally concepts hold the promise of also writing
adapters so that you could write meta-programs that transformed one type into
another compatible with some other part of your code, but I think that part
won't come until later on now.

------
jahnu
Is this just for experimentation or is it planned that this will be more or
less the solution that makes it into the standard?

~~~
octoploid
It is not just for experimentation. The implementation is the basis of a
Technical Specification, that will hopefully make it into C++17.

Finally the TS will be merged into the standard in the further future.

------
emcrazyone
Like others I was struggling to find usefulness of this and what problems it
solves. I admit, it seems like a stretch. There was a situation in which I
needed a template class to be implemented such that I wanted only certain
types to be accepted one way and others a different way.

I implemented a stream buffer that can accept different types into the stream.
Based on the type, the buffer would serialize and expand to accept the data.

To put this more succintly, an insert of unit8_t type would put a single byte
into the stream buffer and an insert of uint16_t would put two bytes into the
stream buffer. And I needed a way to make sure the types were plain old data
types (int, char, uint8_t, uint16_t, uint_32_t, etc...)

Here is sample code:

template<typename T> class TStream { private:

    
    
        typedef TBuffer<T> stream_buffer;
        stream_buffer mStream;
    

public:

    
    
        TStream();
        TStream(const TStream &rhs);
        TStream::~TStream();
    
        unsigned int Size() const;
        unsigned int ByteStreamLength() const;
        void     Clear();
    
      // some methods omitted for brevity
    
        const T&operator[](unsigned int idx);
        const T*operator[](unsigned int idx) const;
    
        TStream<T> &operator=(const TStream &rhs);
        TStream<T> &operator=(T const);
        TStream<T> &operator=(unsigned char);
        TStream<T> &operator=(bool);
        TStream<T> &operator=(double);
    
      // rest omitted for brevity

};

Doing this

TStream<unsigned char> ByteStream

causes ambiguity with

operator=(unsigned char).

I basically want operator=(unsigned char) to be omitted if T = unsigned char.

The way I solved this, without Concepts of course, was to use CRTP like so:

template<typename D, typename T, typename U>

struct implement_operator_plus_equals { implement_operator_plus_equals() {
static_assert(std::is_base_of<implement_operator_plus_equals, D>::value, "CRTP
failure" ); } D* self() { return static_cast<D _> (this); } D const_ self()
const { return static_cast<D const _> (this); }

    
    
      typedef D Self;
    
      Self& operator+=( U u ) {
        static_assert( (sizeof(U)%sizeof(T)) == 0, "Non integer number of Ts in a U" );
        T* b = reinterpret_cast<T*>(&u);
        T* e = b + sizeof(U)/sizeof(T);
        for (T* it = b; it != e; ++it) {
          self()->consume(*it);
        return *self();
      }

}; template<typename D, typename T> struct
implement_operator_plus_equals<D,T,T> { implement_operator_plus_equals() {
static_assert( std::is_base_of<implement_operator_plus_equals, D>::value,
"CRTP failure" ); // Have an operator+= that cannot be called, so using
...::operator+= is legal, // but mostly harmless: class block_call {}; void
operator+=( block_call ) {} } };

I believe I could have solved this without CRTP using Concepts. Although my
understanding is that Concepts follows a methodology of deny all, allow what
is defined and there appears to be no way to allow all, deny what is specified
as a Concept. In other words, Concepts only tell the compiler what is allowed
and there appears to be no way to specify what is NOT allowed without some
further "trickery."

