I agree with that.
> I actually haven't got a clue what the code at the top is doing.
Yes, it's pretty intricate code, using C++14 language features, which
look odd and have strange rules.
Here's a breakdown:
struct Sub
: Text_item
, Itemlist
^ Declares a class called Sub, that inherits from -- Is A -- class
Text_item and from class Itemlist.
What Text_item and Itemlist are doesn't matter.
template< class Item >
^ Introduces a template of something, that can be used with a type that
can be wildly different types in different usage contexts. The concrete
type used in any given context is called Item in this definition.
auto operator<<( Item item ) &&
-> Sub&&
^ The "auto operator<<(" starts a declaration of a member function
called "operator<<". "auto" says that the return type is specified after
the function head, either implicitly via a "return" statement (a C++14
deduced return type) or explicitly via a "->" return type specification
(C++11 trailing return type syntax). The function name "operator<<"
means that this function can be called via operator notation, e.g. the
invocation "o << an_item", which is how e.g. iostreams work.
"( Item item )" is the function's formal argument list, just like in C.
Here an Item is passed by value.
"&&" means that this function can only be called via an rvalue
expression, essentially calling it on a temporary. More precisely it can
also be called on the result of a function that returns an rvalue
reference, because that acts as if it were a temporary. So, the "&&" is
an rvalue qualification of the member function. There are also lvalue
qualification "&", and const lvalue qualification "const &".
-> Sub&&
Specifies that the return type is rvalue-reference-to-Sub, i.e. (as-if)
a reference to a temporary Sub object.
return static_cast<Sub&&>(
move( *this ).Itemlist::operator<<( item )
);
^ This rather ungrokable mess just invokes the base class "operator<<",
and, via the "static_cast", downcasts the result to this class. It
should IMHO have been trivial to do that, it's just a /forwarding/ of
the call to a base class method, but it isn't trivial.
Instead of downcasting the base class' result it could have been
separated into two statements like this:
move( *this ).Itemlist::operator<<( item );
return move( *this );
That's perhaps better for discussion. The "move( *this )" doesn't
actually move anything. It uses "std::move" as a /cast/ to create an
rvalue reference to the current object, needed in the first line because
the base class "operator<<" can only be called via an rvalue expression.
The ".Itemlist::operator<<" then refers to the "operator" defined in the
base class "Itemlist". And the "( item )" expresses the call with "item"
as argument, just like in C.
"move( *this )" is also needed in the return statement, since this
"operator<<", like the one in the base class, returns an rvalue reference.
In the originally posted code there is no "move( *this )" for the result
because that's expressed by a "static_cast".
> However
> in the clc group, C++ is frequently sold as a language which is so much
> easier and better than C because it has so many built-in solutions to
> things that have to be re-implemented in C.
The rvalue stuff in this code addresses problems that stem from what I'd
call a cognitive dissonance in the C++ type system.
The original C lvalue versus rvalue expression classification was
presumably useful to help the compiler put temporary results in
registers, where on most machines one couldn't take the address. Also
one couldn't assign to rvalues. The put-in-registers made for execution
efficiency, and the can't-assign-to made for programmer efficiency; it
all made sense.
In C++ there are rvalue expressions that denote objects of arbitrary
size and complexity, that necessarily do live in main memory, and that
generally /can/ be assigned to. That doesn't make so much sense. So the
code to handle this, with the old distinction still ruling, gets ungood.
> It's odd then that I rarely come across a C++ example which I can follow
> compared to the C equivalent. Or maybe the C++ experts here just like to
> show off their skills at writing incomprehensible code, which is not
> typical of normal programs.
There must be many books and articles about C++ that cater to C
programmers.
If nothing else, I enjoyed learning C++ from the original "The C++
Programming Language" by Bjarne Stroustrup. I think that was published
in 1985. That first edition was of the same general form as the earlier
"The C Programming Language" by Kernighan & Ritchie.
The first edition of TCPPL was about the pre-standard simpler language
that's still to be found within all the complexity of modern C++. I
think that book was before exceptions and templates. Exceptions were
introduced around 1989, IIRC, templates later.
Cheers!,
- Alf