-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
Fix conversion from empty json to std::optional<> #2229
base: develop
Are you sure you want to change the base?
Conversation
Is the following really needed?
|
That assertion held true so far. If that changes now, this may indicate a breaking change. |
Modified |
There are no identical bases. Moreover, direct identical bases are not allowed. |
As i said in #2213, this is why an exception is raised when calling |
test/src/unit-conversions.cpp
Outdated
std::optional<std::string> opt_null; | ||
|
||
CHECK(json(opt_null) == j_null); | ||
CHECK_THROWS_WITH(std::optional<std::string>(j_null), |
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.
Weird. In my local env, the exception would not raise. By from CI online logs , it will get the exception.
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.
What is special in your local environment?
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.
ubuntu 18.04
gcc 7.4
cmake 3.10.2
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.
Somewhat has changed since GCC 7.4
https://godbolt.org/z/4MfL8i
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.
There is probably a bug in GCC 7. When used with "-std=c++17" it may perform wrong overload resolution for user-defined conversion. In previous example and also here (with no std::optional
involved) it behaves as if the implicit copy constructor is selected, whereas there is a more suitable template constructor. Other major releases of GCC (including older versions) prefer template constructor.
I do not like this approach. I cannot believe this is an issue in |
Are there specific STL implementations where the issue with |
It seems the issue is caused by |
MSVC has bad |
What is more, |
test/src/unit-concepts.cpp
Outdated
// should return true | ||
return std::is_standard_layout<D>::value; |
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.
Microsoft doesn't consider their implemenation wrong. Their story is about empty base optimization, backward binary compatibility and non-standard extension __declspec(empty_bases)
which can be used to achieve standard behavior.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
b1b8528
to
76a83a9
Compare
Same question as with #2117 - how to proceed here? |
Here is a "better" |
@karzhenkov This PR is conflicting again. Can you update? |
e0ff46c
to
b7a5d99
Compare
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'd like to evaluate this branch in one of my projects to make sure there aren't any ugly side effects. Afterward, I'll come back for a more in-depth review.
@@ -51,15 +51,15 @@ using nlohmann::json; | |||
// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair | |||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH | |||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") | |||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-macros") |
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.
Would it be better to just move the *_CONVERSION_WARNING
macros into the #if JSON_HAS_CPP_17
block?
You're getting this warning because, in the C++11 build, the macros aren't used.
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 considered it, but I think it's hardly much better. I preferred a slightly more concise variant.
It's not clear if |
FYI: I suppressed the warnings for non-explicit constructors in Codacy. |
f1dee7b
to
4168189
Compare
The remaining problems are related to three-way comparisons in C++20. I hope to fix them when I have time. |
The problem boils down to the following example, which complies in C++17 but not in C++20: #include <optional>
struct opt : std::optional<int> {};
bool operator == (const opt&, const opt&);
bool operator >= (const opt&, const opt&);
int main()
{
sizeof(opt() == opt());
sizeof(opt() >= opt());
} If any of the operator declarations is removed along with the corresponding check, the code compiles regardless of the language standard. |
Digging a little bit deeper, the code triggers a recursion in Adding a specilization to namespace std {
template<>
inline constexpr bool __is_optional_v<opt> = true;
} How do we work around this? |
4168189
to
3854934
Compare
It looks like a defect in the C++20 standard (or maybe in the standard library implementation). I think it is impossible to correctly define comparisons for a class derived from |
Here is possible solution (or workaround) for issues in PR #2117, #2213.
The problem is caused by "wrong" user defined conversion selected by overload resolution. Compiler selects a converting constructor for
std::optional<std::string>
, whiletemplate <...> json::operator ValueType
is needed. This behavoir is correct becausejson
can be implicitly converted tostd::string
. The constructor is unaware aboutfrom_json
function."Non-template" version of conversion operator presented here "adjusts" the resolution process. However, the desired result is achieved for copy initailization only. Direct initialization still selects the converting constructor (this probably cannot be changed).