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 :)
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 ).
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.
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."
Constraints on template types are useful outside of metaprogramming proper. For example, the standard library already specifies classes of iterators dependent on e.g. the direction(s) in which they may be advanced.
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++.
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"
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".
I revisited the concepts pdf (which can be found in the original post) and it has a `requires` statement, which allows
to combine multiple constraints on the types of a templated construction.
This would allow to write (your `Cloneable Iterator` idea)
template <ForwardIterator T>
requires CopyConstructible<T>
void copy(T a, T b)
Java Interfaces and C++ Concepts: the later being much more open, and Java interfaces being closed under types (C++ requires statement can have boolean const expressions in them)
I think the definition of good concepts is going to be hard that is for sure, however when one find a good one (one that can be shared within a programming community the way mathematical concepts are shared) then it will convey just the right amount of information for a community to understand the code they share.
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!
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.
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...)
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."
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.
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.
That was kind of my impression, from the discussion in Alexander Stepanov and Daniel Rose's From Mathematics to Generic Programming (which is a pretty decent book, by the way).
My understanding[1] is that concepts act like a type system for templates and like typeclasses in Haskell and traits in Rust.
https://en.wikipedia.org/wiki/Concepts_(C%2B%2B)