-
Notifications
You must be signed in to change notification settings - Fork 37.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 fa74f6c, 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. |
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 fa540a3
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
* To use, place this as the last line into a class or struct. | ||
*/ | ||
#define DISABLE_IMPLICIT_COPIES(T) \ | ||
T() = default; \ |
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" (fa540a3)
Can drop default constructor? Seems orthogonal to copy/move stuff
src/util/types.h
Outdated
\ | ||
private: \ | ||
T& operator=(const T&) = default; \ | ||
T(const T&) = default |
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" (fa540a3)
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 default
ing.
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
deleted
function can not be "recovered" bydefault
ing.
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
/CopyFrom
macro 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 |
@@ -117,7 +110,11 @@ struct CSerializedNetMsg { | |||
|
|||
std::vector<unsigned char> data; | |||
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