-
-
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
Perplexing template deduction failure serialising a 3rd party type using base class #3267
Comments
could you provide information about your setup as specified in the bug-issue-template https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE/Bug_report.md |
I have updated my pose with my setup at the end |
what compiler are you using? Have you tried with the current version of |
I've just checked out an installed the latest release, 3.10.5, and made a basic With method 1, I am able to encode to json but not decode from json (this is an improvement compared to version 3.9.1 I was on before). With method 2, I am not able to encode or decode. As before, if I static cast to the base class type, the conversion works. Each of these permutations is shown in the following code. |
@willat343 I haven't dug into this in detail, but it's likely because the type is designed to be used as an array, and thus has an interface that matches "can serialize this using the built-in array serialization". Have you tried to see if removing these |
@gregmarr that's a plausible hypothesis, however removing the Edit from future me: this is quite a long comment, because I think i've worked out the issue. I wrote the following during my investigation. Encoding fails with:
Decoding fails with:
Trying to work through this, it seems to be using the overload:
This is still a bit hard to read, so here is the function:
As someone who doesn't know The compiler then fails to compile line 18955, which is in fact
with The type trait is defined as:
which leads us to
I believe it is using the 1st one since the other 4 are templated with pairs/tuples, and hence my hypothesis is that SO! Taking this hypothesis and writing the following basic program, we find that indeed
Prints "passed!" three times. A little more experimentation reveals that you can construct from an empty string object:
but not from a non-empty string:
Looking through the constructors of Matrix (https://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html), I believe the problematic one is Matrix (Index dim) where
I tried a simple test class:
But strangely this failed with a note that surprised me given what I'd just tested: I think i'll put an issue in with the |
@willat343 Have you run this under the debugger so you can step in and see for sure what constructor is called? I looked at the header, and the actual constructors are a bit different than what's in the docs due to a couple template constructors that chain to the base class init function.
|
@gregmarr I will do that and report back |
I tried a few methods, but was not able to generate a breakpoint on the matrix constructor with Even so, i've openned up an issue with the Eigen devs here. I do wonder, though, if there is a subtle |
Ok, the Eigen devs correctly pointed out that In my previous analysis, I was looking at the compilation error when no specialisation was given, hoping to gain insight into the problem. When the specialisation is given (method 1), the compilation error is:
Breaking this down:
It is at line 4273,
So my question is then: why is it selecting this function over my specialisation? should it not complain about function ambiguity when you have two valid from_json functions? (I imagine there would be other cases where one can construct from string but also specialise their from_json function) Now testing method 2, compilation of decoding fails with the same error:
This implies to me that the adl_serializer specialisation is not being found at all.
|
Yeah, that's what I thought.
Your specialization takes a base class reference. This function takes a reference of the exact type of the object. Thus, this function is a better match.
I think this template parameter should be named something like
Yes, that does seem to be accurate. You have a type that is constructible from a string but can not be assigned to from a string, and this is doing assignment, not construction, so it should be looking at assignment. |
I'm running into this same issue with Eigen. Is there any currently any recommended way of working around this? |
@nickanthony-dgl It is not possible currently to use the I am not sure how to resolve the apparent subtle bug in the json api discussed in the last few comments (check for assignment not construction). I am hoping a json and/or type-traits expert can offer some guidance here. I am also not sure if there will be much progress on the |
Constrain from_json() overload for ConstructibleStringType to not accept json_ref and require assignability. Re-enable C++14 tests on Clang <4.0. Fixes nlohmann#3171, nlohmann#3312, nlohmann#3384. Maybe fixes nlohmann#3267.
Constrain from_json() overload for ConstructibleStringType to not accept json_ref and require it to be assignable from basic_json::string_t. Re-enable C++14 tests on Clang <4.0. Fixes nlohmann#3171. Fixes nlohmann#3267. Fixes nlohmann#3312. Fixes nlohmann#3384.
Constrain from_json() overload for StringType to not accept json_ref and require it to be assignable, instead of constructible, from basic_json::string_t. Re-enable C++14 tests on Clang <4.0. Fixes nlohmann#3171. Fixes nlohmann#3267. Fixes nlohmann#3312. Fixes nlohmann#3384.
@falbrechtskirchinger I'm on nlohmann/json v3.11.3, and Method 2 (with |
I know (and have checked with a basic code example) that if a serialisation is defined for a base class/struct, then derived classes can be serialised too without additional code (the derived classes are equivalent to the base in the json). For example the following code works as intended:
I am facing an equivalent issue with a 3rd party type, in particular
Eigen
matrices/vectors, which seems to have nothing to do with the contents of the serialisation functions themselves, but the deduction that these to_json/from_json functions need to be used in the template deduction. The following code (which i do not want to use for reasons I will discuss in a moment) is tested and works as intended:(note that Matrix4f is a typedef for Matrix<float, 4, 4>)
As described in their documentation (https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html), it is more general and powerful to templatise according to an appropriate base class which will permit serialisation of a wider group of eigen structures. Noting that
Matrix4f
inherits fromMatrixBase<Matrix4f>
, the following serialisation functions should work identically:This does not compile, with the first part of the error log (to me) showing that it is not deducing that it should use these serialisation functions, but instead trying to use an array type converter (
void nlohmann::detail::to_json(BasicJsonType&, const CompatibleArrayType&) [with BasicJsonType = nlohmann::basic_json<>; CompatibleArrayType = Eigen::Matrix<float, 4, 4>
...):If I static cast to the base class, to_json works (although this is obviously not a solution):
yeilds
[[1.0,2.0,3.0,4.0],[11.0,12.0,13.0,14.0],[21.0,22.0,23.0,24.0],[31.0,32.0,33.0,34.0]]
as it should.I am stumped. Has this template deduction issue arisen before? Any ideas what I might be doing wrong?
Setup:
develop
branch at commit 6471a63 from mid-2021, which is part of version 3.9.1The text was updated successfully, but these errors were encountered: