Date: Tue, 23 Jul 2019 21:44:45 -0400
On Tue, Jul 23, 2019 at 8:31 PM Joshua Cannon via Std-Proposals <
std-proposals_at_[hidden]> wrote:
>
> As a (contrived) example, let's say I have a class (called Foo) that
> takes in a const-reference to a vector. It is going to store a reversed
> copy of the vector with all of the elements also incremented as a member.
> Additionally, it is going to have a member of type Bar, which is
> constructed by taking in iterators to the reversed-and-incremented vector.
> There's no easy way to do that today. Some solutions might be [...]
>
A proposal with this degree of "real-estate claimage" needs to have better
motivation than a single contrived example where you already know how to
work around it anyway.
I say that your proposal claims a lot of syntactic (and mental) real-estate
because it appears to collide with the long-desired feature of
"member-initializer-list with trailing comma." Consider:
struct S1 {
int x, y, z;
S1() : x(1), y(2), z(3),
{}
};
Under your proposal, IIUC, this would be ill-formed code: the compiler
would see `};` when it was expecting another `,` followed by a
member-initializer. But there's already a fair bit of support (from the
machine-generated-code crowd) for this to be well-formed and for the
compiler to simply ignore the trailing `,` after z's member-initializer.
You could certainly deal with this by tweaking your proposed syntax — like
maybe interpose some sort of keyword, or use `( ... )` instead of `{ ... }`
to delimit your code blocks, or whatever. But that brings me back to the
proposal's very weak motivation (about which, more below).
You also mentioned another syntactic issue that I think is a bigger deal
than you're making it. Consider
struct S2 {
int x, y, z;
S2(int) : x(1), { ++x; }, y(2), z(3) {}
S2(short) : x(1), { ++(this->x); }, y(2), z(3) {}
S2(char) : x(1), { S2 *p = this; ++(p->x); }, y(2), z(3) {}
};
Is `S2(int)` well-formed? You'd say "yes," obviously.
Is `S2(short)` well-formed? It's just syntactic desugaring of `S2(int)`,
right?
Is `S2(char)` well-formed? If so, then how do you propose to stop people
from accessing `p->y`?
Lastly, you haven't mentioned what you'll do about
struct S3 {
int x, y, z;
S3(int) : z(3), { puts("hello"); }, y(2), { puts("world"); }, x(1) {}
};
nor
struct S4 {
int x, y, z;
S4(int) : x(1), { return; }, y(2), z(3) { puts("so this is never
reached?"); }
};
Okay, now I want to return to the weak motivation, by showing how I'd
refactor your example code to work in today's C++.
Example:
>
> class Foo {
> std::vector<int> myVec;
> Bar bar;
>
> public:
> Foo(const std::vector<int>& inVec):
> myVec(inVec.rbegin(), inVec.rend()),
> {
> std::transform
> (
> myVec.begin(),
> myVec.end(),
> myVec.begin(),
> &[](int i){return ++i;}
> );
> },
> bar(myVec.begin(), myVec.end())
> {}
> };
>
I would write this as
class Foo {
std::vector<int> myVec;
Bar bar;
public:
explicit Foo(const std::vector<int>& inVec) :
myVec(rev_and_inc(inVec)),
bar(myVec.begin(), myVec.end())
{}
private:
static std::vector<int> rev_and_inc(const std::vector<int>& inVec) {
std::vector<int> result(inVec.rbegin(), inVec.rend());
for (int& elt : result) ++elt;
return result;
}
};
This code is exactly as efficient as the code you wrote, thanks to copy
elision. It's also easier to read. It's also portable to C++11 compilers.
(In fact, the only reason it's not valid *C++03* is because I turned your
`std::transform` into a C++11 for-loop for readability's sake.)
I hesitate to claim that you'll never find *any* sufficient motivation for
your proposal, but the code you've presented certainly isn't sufficient
motivation to justify a language change (let alone a language change that
claims so much useful real-estate).
HTH,
–Arthur
std-proposals_at_[hidden]> wrote:
>
> As a (contrived) example, let's say I have a class (called Foo) that
> takes in a const-reference to a vector. It is going to store a reversed
> copy of the vector with all of the elements also incremented as a member.
> Additionally, it is going to have a member of type Bar, which is
> constructed by taking in iterators to the reversed-and-incremented vector.
> There's no easy way to do that today. Some solutions might be [...]
>
A proposal with this degree of "real-estate claimage" needs to have better
motivation than a single contrived example where you already know how to
work around it anyway.
I say that your proposal claims a lot of syntactic (and mental) real-estate
because it appears to collide with the long-desired feature of
"member-initializer-list with trailing comma." Consider:
struct S1 {
int x, y, z;
S1() : x(1), y(2), z(3),
{}
};
Under your proposal, IIUC, this would be ill-formed code: the compiler
would see `};` when it was expecting another `,` followed by a
member-initializer. But there's already a fair bit of support (from the
machine-generated-code crowd) for this to be well-formed and for the
compiler to simply ignore the trailing `,` after z's member-initializer.
You could certainly deal with this by tweaking your proposed syntax — like
maybe interpose some sort of keyword, or use `( ... )` instead of `{ ... }`
to delimit your code blocks, or whatever. But that brings me back to the
proposal's very weak motivation (about which, more below).
You also mentioned another syntactic issue that I think is a bigger deal
than you're making it. Consider
struct S2 {
int x, y, z;
S2(int) : x(1), { ++x; }, y(2), z(3) {}
S2(short) : x(1), { ++(this->x); }, y(2), z(3) {}
S2(char) : x(1), { S2 *p = this; ++(p->x); }, y(2), z(3) {}
};
Is `S2(int)` well-formed? You'd say "yes," obviously.
Is `S2(short)` well-formed? It's just syntactic desugaring of `S2(int)`,
right?
Is `S2(char)` well-formed? If so, then how do you propose to stop people
from accessing `p->y`?
Lastly, you haven't mentioned what you'll do about
struct S3 {
int x, y, z;
S3(int) : z(3), { puts("hello"); }, y(2), { puts("world"); }, x(1) {}
};
nor
struct S4 {
int x, y, z;
S4(int) : x(1), { return; }, y(2), z(3) { puts("so this is never
reached?"); }
};
Okay, now I want to return to the weak motivation, by showing how I'd
refactor your example code to work in today's C++.
Example:
>
> class Foo {
> std::vector<int> myVec;
> Bar bar;
>
> public:
> Foo(const std::vector<int>& inVec):
> myVec(inVec.rbegin(), inVec.rend()),
> {
> std::transform
> (
> myVec.begin(),
> myVec.end(),
> myVec.begin(),
> &[](int i){return ++i;}
> );
> },
> bar(myVec.begin(), myVec.end())
> {}
> };
>
I would write this as
class Foo {
std::vector<int> myVec;
Bar bar;
public:
explicit Foo(const std::vector<int>& inVec) :
myVec(rev_and_inc(inVec)),
bar(myVec.begin(), myVec.end())
{}
private:
static std::vector<int> rev_and_inc(const std::vector<int>& inVec) {
std::vector<int> result(inVec.rbegin(), inVec.rend());
for (int& elt : result) ++elt;
return result;
}
};
This code is exactly as efficient as the code you wrote, thanks to copy
elision. It's also easier to read. It's also portable to C++11 compilers.
(In fact, the only reason it's not valid *C++03* is because I turned your
`std::transform` into a C++11 for-loop for readability's sake.)
I hesitate to claim that you'll never find *any* sufficient motivation for
your proposal, but the code you've presented certainly isn't sufficient
motivation to justify a language change (let alone a language change that
claims so much useful real-estate).
HTH,
–Arthur
Received on 2019-07-23 20:46:55