Not strictly correct. A concept is a set of assumptions that are made about a type. These assumptions are formalized as a set of nested types in the type, operations you can perform on the type, and similar. However, the documentation of a concept will usually carry additional semantic requirements on these operations.
Originally Posted by Mario F.
If you're familiar with Java-like, .Net-like or COM-like interfaces, a concept could be called a compile-time interface.
It's not a base class or abstract class or anything like that. Concepts are purely compile-time constructs, enforced for template parameters at compile time. Several different template parameters will still spawn several instantiations, even if they conform to the same concept. The for_each implementations might look like this:
That type, "Container", is the so called Concept. It seems it will be nothing more than an abstract class of which the container types will derive.
Pass in a container, and the compiler will notice that it conforms to the InputRange concept (it has a begin() and an end(), both of which return InputIterators), so it will choose the second overload. It will then instantiate a version that is specific to that particular container. No runtime switches.
template<typename InIt, typename Fn> where <InputIterator<InIt>, UnaryFunction<Fn>>
Fn for_each(InIt first, InIt last, Fn fn)
for( ; first != last; ++first) fn(*first);
template<typename Rng, typename Fn> where <InputRange<Rng>, UnaryFunction<Fn>>
Fn for_each(Rng rng, Fn fn)
return for_each(rng.begin(), rng.end(), fn);
And many refinements of Iterator, and Range and its refinements, and of course all the concepts you can define yourself. Not to mention DefaultConstructible, CopyConstructible, Assignable, and many other things that make useful restrictions on arguments to the STL.
Other concepts will probably be Iterator and possibly(?) more specialized versions of the Container concept, like SequencialContainer(?) and AssociativeContainer(?).
I don't see how.
Will this not make templating around STL objects harder to achieve?
Perhaps, but the purpose of concepts is to document the assumptions that are valid, and enforce them.
There cannot be many assumptions about the type inside the templated function or class.
Not at all! Consider what happens if I pass my own custom class ostream_range to for_each. ostream_range has begin() and end(), which return ostream_iterators. ostream_iterators, as is obvious, conform to the OutputIterator concept. Thus, ostream_range conforms to the OutputRange object.
STL objects are invariably very different objects among themselves. So, it seems to me almost useless to create a template with Concept parameters.
OK, what happens on a C++98 compiler, which has the above overloads of for_each, but no concept checking - it relies on the argument count for the overload.
Most likely, I'll get an error message from inside the three-argument for_each, which says something like
And I'm like, Huh?
ERROR C9783 C:\long\path\to\standard\includes\algorithm (214): Cannot convert
std::ostream_iterator<_Element>::__assign_proxy to int - no appropriate conversion operator found
_Element = int
C:\long\path\to\standard\includes\algorithm (212): in std::for_each(_InIt __first, _InIt __last, _Fn __fn)
_InIt = std::ostream_iterator<int>,
_Fn = void (*)(int)
C:\long\path\to\standard\includes\algorithm (227): instantiated from std::for_each(_Rng __rng, _Fn __fn)
_Rng = cornedbee::tools::ostream_range<int>,
_Fn = void (*)(int)
D:\work\projects\example\faulty.cpp (44): instantiated from here
Now let's take the C++0x compiler and see what it gives me:
A lot more informative, wouldn't you say?
ERROR C8320 D:\work\projects\example\faulty.cpp (44): Cannot pass orng to std::for_each(_Rng __rng, _Fn __fn):
Object does not fulfill the InputRange concept.
Where is the danger?
In fact, it seems a recipe for disaster except for very specific situations that perhaps wouldn't warrant such a big change to the STL.
It won't. As I said, concepts are a purely compile-time mechanism. There is no trace of them left at runtime.
Also, will this not add a lot of weight to the STL performance? Every STL object being now inside a OO structure with a base abstract class, especially when accessed through a pure virtual function, will be leaps and bounds slower than the current design. Won't it?
Not that I know of. I don't think it was ever valid to use the auto storage modifier without an actual type. It will still exist as a storage modifier. (As such, "auto auto" should be valid.)
This one boggles me to no end. the auto keyword is dropped of its previous use
Indeed. Very, very important syntactic sugar, if you've ever played with complicated types like Boost.Spirit's parsers.
and is now used to define an object of which type is infered from the initializer. So...
int foo = 12;
auto bar = foo; // bar type is obtained by infering the type of foo. bar is an int.
From what I have read this is nothing but syntactic sugar.
Nothing does. Except this: right now, hardly anybody uses const_iterator if the source object isn't const, because it's too much to write. If the object IS const, then the compiler will correctly deduct const_iterator for auto. The non-const version of begin() won't be considered, because the object is const.
What will distinguish const_iterator from iterator? Surely not the compiler! Will it?
Also, there's a proposal to add cbegin() and cend() etc. to all containers that are not overloaded on constness. I'm not sure if that proposal will go through.
Uh ... there is no such type as an unsigned long double. The type of a suffix-less decimal constant expression is double, and that will be the deduced type of x, too. There's absolutely no ambiguity there, and no implicit conversion rules come into play. The nice thing about auto is that you're guaranteed there won't be any conversion on initialization.
And what more... literals. What to say of auto x = 12.5? It seems logic to believe that the implicit conversion rules will dictate the type of x. But according to these rules x would be a unsigned long double. Highly excessive, don't you think?
No, it isn't at all machine-dependent. The types of literals are well-defined by the standard.
It will also introduce yet another machine dependant construct.
You can just do the same as the compiler does and deduce the type of the object from its initializer.
But what makes this one worst is that the auto keyword will explicitly hide the type of the object... forever! Only through RTTI will it be possible to effectively debug the code. Worst, there's no RTTI for built-in types. So... What on earth! Am I missing something?
No. As I said, the auto keyword will retain its functionality as a storage modifier.
But more importantly, and this is what boggles me more, will this not break backwards compatibility with C?
You might want to be very careful with such statements. Backwards compatibility always was and still is a stated goal of C++.
Originally Posted by ssjnamek