You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Conceptually, I think the problem is that Testcan be converted to an int, but the assignment j["test"] = t; does not require t to be an int. You could, for instance, add another operator bool() { return x > 0; } or operator std::string() { return std::to_string(x); } and it is ambiguous which operator to take to create a json object.
I think this may be related to the fact that basic_json has multiple constructors accepting types that int may be converted to. j["test"] = static_cast<int>(t) should work.
@nlohmann I'm a bit late to respond, sorry. I don't agree with your statement, here's an example to illustrate:
voidfoo(bool);
voidfoo(int);
structTest {};
Test t;
foo(t); // error: Test can't be converted to bool or int
Nothing surprising here, but once you add operator int to Test the code compiles and works as expected. Once you add operator bool you run into ambiguous function call as per normal language rules.
If built-in types can be added to json I don't see why types that are convertible to builtins shouldn't be?
@TurpentineDistillery I don't think that's true, the problems seems to be the templated assignment operator that will match the exact type being assigned and not consider any conversions. Assigning an int selects a different overload.
@popizdeh What do you think of my initial comment? I still do not see how a compiler should find out how a json object can be constructed from a Test object.
I don't know how easy this would be, I might look into it a bit more when I get some spare time, but in a nutshell we need to change the template assignment operator because it's always a better match. If json supports ints then it needs to support all types that are convertible to int. We just need to find a way to write that assignment operator differently so that implicit conversions are taken into account.
So far, for each value type (array, object, string, boolean, floating-point number, unsigned integer number, and signed integer number), we have a constructor like
The problem with this is that it only works for classes whose conversion operator type exactly matches one of basic_json's constructor parameter types. So having a type that implicitly converts to unsigned int still doesn't work as it doesn't know what constructor to select, bool, const int and float are all equally good.
You could add a Test::operator json() to fix the original issue, but that requires that you can modify Test.
Maybe there's a way to do it via a free function? For example, add a SFINAE constructor to basic_json that accepts any type T where the call "to_json(the_t_value)" works?
I guess I could add an operator to my class, or I'll just live with static_cast.
I don't think it's worth going overboard for this. It'd be nice to have but I was hoping there'd be a simple solution. Feel free to close this Niels, I'll send you a patch if I get a better solution.
Activity
nlohmann commentedon Nov 25, 2016
Conceptually, I think the problem is that
Testcan be converted to anint, but the assignmentj["test"] = t;does not requiretto be anint. You could, for instance, add anotheroperator bool() { return x > 0; }oroperator std::string() { return std::to_string(x); }and it is ambiguous which operator to take to create ajsonobject.TurpentineDistillery commentedon Nov 28, 2016
I think this may be related to the fact that
basic_jsonhas multiple constructors accepting types that int may be converted to.j["test"] = static_cast<int>(t)should work.popizdeh commentedon Dec 7, 2016
@nlohmann I'm a bit late to respond, sorry. I don't agree with your statement, here's an example to illustrate:
Nothing surprising here, but once you add
operator inttoTestthe code compiles and works as expected. Once you addoperator boolyou run into ambiguous function call as per normal language rules.If built-in types can be added to json I don't see why types that are convertible to builtins shouldn't be?
@TurpentineDistillery I don't think that's true, the problems seems to be the templated assignment operator that will match the exact type being assigned and not consider any conversions. Assigning an int selects a different overload.
nlohmann commentedon Dec 11, 2016
@popizdeh What do you think of my initial comment? I still do not see how a compiler should find out how a
jsonobject can be constructed from aTestobject.popizdeh commentedon Dec 11, 2016
I don't know how easy this would be, I might look into it a bit more when I get some spare time, but in a nutshell we need to change the template assignment operator because it's always a better match. If json supports ints then it needs to support all types that are convertible to int. We just need to find a way to write that assignment operator differently so that implicit conversions are taken into account.
nlohmann commentedon Dec 12, 2016
So far, for each value type (array, object, string, boolean, floating-point number, unsigned integer number, and signed integer number), we have a constructor like
is_constructibleseems not to take implicit conversions into account.I am not sure how an extension to implicit conversions would look like, and whether it would help rather than add new ambiguities.
nlohmann commentedon Dec 22, 2016
Any ideas on this?
popizdeh commentedon Dec 23, 2016
I had a quick look, here's what I have so far. Adding a templated assignment operator gets us a bit closer to what I had in mind.
The problem with this is that it only works for classes whose conversion operator type exactly matches one of basic_json's constructor parameter types. So having a type that implicitly converts to
unsigned intstill doesn't work as it doesn't know what constructor to select, bool, const int and float are all equally good.nlohmann commentedon Jan 2, 2017
Any ideas how to proceed here?
jaredgrubb commentedon Jan 2, 2017
You could add a
Test::operator json()to fix the original issue, but that requires that you can modifyTest.Maybe there's a way to do it via a free function? For example, add a SFINAE constructor to basic_json that accepts any type T where the call "to_json(the_t_value)" works?
popizdeh commentedon Jan 3, 2017
I guess I could add an operator to my class, or I'll just live with static_cast.
I don't think it's worth going overboard for this. It'd be nice to have but I was hoping there'd be a simple solution. Feel free to close this Niels, I'll send you a patch if I get a better solution.
nlohmann commentedon Jan 3, 2017
Maybe #328 will be a solution for this. Good that you don't mind closing this. I you find a solution, I'm all ears.
theodelrieu commentedon Jan 22, 2017
I do think #423 will be the solution, I just added tests with implicit conversions, and it seems to work well.
EDIT: You will need a
to_jsonmethod in order to get it working, the ambiguity with the conversion operator will remain if you don't