On 04-Jun-17 11:39 AM, Christiano wrote:
> There is a bug in the book PPP2[1] that made me wonder what would be
> the reasons for C ++ to accept X{1,2,3,4} to be the same thing as
> X{{1,2,3,4}}.
>
> The bug is:
> "The string{1,c} is a constructor for string, initializing the string to
> contain the single character c."
>
> No. The string{1,'a'} will create a vector with two elements: 1 and 97
> ('a' ascii value).
> The correct should be string(1,c).
Right, except formally the presumption of ASCII.
> Proof:
Careful. The result from a given implementation is not proof of
anything. It can support an argument and serve as an heuristic.
The final authority on C++ is the C++ standard.
But in this case the behavior is well known so you don't need to supply
a proof: you only need to point out the error. For example, the
idiomatic way to create a single character string is `string{c}`, which
relies on the same precedence for initalizer list overload, and which
doesn't work with round parenthesis. At a guess Bjarne originally wanted
the curly braces syntax to be a drop-in replacement for the original
round parenthesis syntax, but it didn't work out that way.
> [snip]
> car v{1};
> car u{{1,2,3}};
> car t{1,2,3};
> // car r{{{1,2,3}}}; ERROR
> What I want to discuss here is: Wouldn't a result similar to following
> be more reasonable?:
>
> v using car(int n)
> u using car(initializer_list<int> lst)
> t using car(int, int, int) ---> ERROR because you haven't defined
> car(int, int, int) here
>
> My point here is: The compiler forbidding X{1,2,3,4} being equal to
> X{{1,2,3,4}}:
>
> 1- would be orthogonally compatible with the error of writing r{{{1,2,3}}}
> 2- Prevents mixing of C++98 syntax (x(1)) with C++11 syntax (x{1})
As I recall in the original C syntax internal braces in an initializer
were optional. Optional is a one-way thing. You can omit but you can
generally not add.
> Is there any special reason to X{1,2,3,4} being equal to X{{1,2,3,4}} in
> spite of the benefits that language would gain without it??
E.g. `std::array`, or more precisely the original `boost::array`, since
the standard library can any kind of magic, relies on this.
The issues we have now with that syntax were not possible, and hence not
considered, in early C, or for that matter in modern C.
When you design a new class it's easy to avoid the problem by e.g.
adding a tag argument to the value list constructor:
#include <iostream>
#include <initializer_list>
using namespace std;
namespace with {
struct Values {} const values = {};
} // namespace with
class Car
{
public:
Car( int )
{
cout << "<init>( int )" << endl;
}
Car( with::Values, initializer_list<int> const values )
{
cout << "<init>( initializer_list ) " ;
for( auto const x : values ) { cout << x << " "; }
cout << endl;
}
};
auto main()
-> int
{
Car v{ 1 }; // int
Car u{ with::values, {1,2,3} }; // values
// Car t{1,2,3}; //! error
// Car r{{{1,2,3}}}; //! error
}
Cheers & hth.,
- Alf