-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Re-enable C++20 aggregate initialization for CSerializedNetMsg #24641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "2203-copy-move-\u{1F33A}"
Conversation
|
Concept ACK fa74f6c5390a433342ce04359f592483a8d8cf97, but I think it would be worth trying to improve the macro if it is going to spread. I was initially confused by PR description, but it seems like problem this solves is that C++20 forbids aggregate initialization if a class has any constructors, while C++17 allows it and lets you have constructors and aggregate initialization together at the same time. Because we want to use aggregate initialization, we will be forced to get rid of some constructors when we update to c++20, and the macro helps work around that. I'm not sure this macro is ideal, though, and I think it might be good to try to improve it. I'm mainly concerned it will be applied places it doesn't belong. Two cases where no-copy-only-move behavior is useful are:
I don't think we have a lot of examples of the second case, so can probably ignore it. But for the first case, the macro sucks a little because it disable copying entirely instead of disabling copying by default which makes code annoying to work with and test, especially since when you test you often do want to be able to copy entire data structures. Also starting the name with AGGREGATE_ probably means developers will apply macro to aggregate initialized structs freely, which will make this even more annoying. I think a better version of this macro would be called something like |
fa74f6c to
fa540a3
Compare
|
Thx, edited OP/title and reworked code. |
ryanofsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Code review ACK fa540a3c5a08c06917a3df1b3d42939eab757f5e
It might be good to add a simple unit test to make sure aggregate initialization works, and check that https://en.cppreference.com/w/cpp/types/is_copy_constructible is false
src/util/types.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Add DISABLE_IMPLICIT_COPIES helper" (fa540a3c5a08c06917a3df1b3d42939eab757f5e)
Can drop default constructor? Seems orthogonal to copy/move stuff
src/util/types.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit "Add DISABLE_IMPLICIT_COPIES helper" (fa540a3c5a08c06917a3df1b3d42939eab757f5e)
I think after adding C++20 support might need to drop these T constructors and go back to using the NoCopyOnlyMove _no_copy_only_move empty member trick, because according to p1008 if a class has any user-declared constructors it will no longer be an aggregate.
This only applies to constructors, not operator= methods, though, so I think private operator= method would be able to stay, and CopyFrom method would not have to change. Copy method might need to change to T Copy() const { T copy; copy = *this; return copy; }.
But it might make sense keep this current implementation for now and change it if needed in the C++20 PR later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like an implicitly deleted function can not be "recovered" by defaulting.
warning: explicitly defaulted copy assignment operator is implicitly deleted [-Wdefaulted-function-deleted]
error: object of type 'CSerializedNetMsg' cannot be assigned because its copy assignment operator is implicitly deleted
Thus, it seems impossible to have a Copy/CopyFrom macro and aggregate initialization that works with both C++17 and C++20.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like an implicitly
deletedfunction can not be "recovered" bydefaulting.
I don't think the followup I'm suggesting should cause the copy asssignment operator to be implicitly deleted, so there be no need to recover it. But the PR in its current form seems fine, and we can iterate on it. If iteraton requires dropping explicit Copy methods to support c++20, that seems sad but not tragic.
Thus, it seems impossible to have a
Copy/CopyFrommacro and aggregate initialization that works with both C++17 and C++20.
I'm not convinced of this, but there's no need to solve it now, and I think the macro here already provides an improvement. It would be good to have a unit test to check that the macro allows all the things it is supposed to allow in c++17. If it has to drop support for some of those things in c++20, the test could catch that and be updated at that time to reflect this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced of this
Heh, what about you open a pull to prove me wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced of this
Heh, what about you open a pull to prove me wrong?
I can try later, but I like this PR because it adds a simple and clean macro for c++17. If the macro has to get messier or stupider later to support c++20, I think it's better if that happens in a followup PR adding c++20 support than in an earlier PR before we are even allowed to use c++20 features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking is that it is possible to achieve without a macro, manually implementing Copy/CopyFrom as seen here: https://github.com/bitcoin/bitcoin/pull/24169/files#diff-422879cc8bfac56d4380c865f381b58afeb344bc355bbc7f47c581e4491b6b4b
I will rebase this pull after #24169 and probably drop the Copy/CopyFrom from the macro. If there is a way to achieve them with a macro, it can be done later.
fa540a3 to
fa57a80
Compare
fa57a80 to
fada2c9
Compare
|
I've reverted this pull to the initial version |
| std::string m_type; | ||
|
|
||
| // No implicit copying, only moves. | ||
| DISABLE_IMPLICIT_COPIES(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a field to a struct/class will always increase its size, even if the added type is empty (because no object can have size 0). As an alternative, does inheriting from Disable_Implicit_Copies work (you can inherit from an empty struct without increasing size).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the language in p1008 "An aggregate is an array or a class with no user-provided, explicit,user-declared or inherited constructors" this would make the class no longer compatible with aggregate initialization in c++20
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The paper recommended to use no_unique_address for the field. Though, that is C++20 only: https://en.cppreference.com/w/cpp/language/attributes/no_unique_address
|
Closing, as it seems impossible without downsides |
I think this is a nice macro that can be used to disable implicit copies, but allow moves.
This is also required in the context of C++20 to re-enable aggregate initialization, which have been disabled in commit 213e98c. This pull request is inspired by section 3.3 of the paper http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1008r1.pdf