toml11 icon indicating copy to clipboard operation
toml11 copied to clipboard

Type conversion between numeric types

Open luketpickering opened this issue 3 years ago • 3 comments

In the README it mentions that conversion between int/floating cannot be done implicitly. Is this really not possible? If a user wants to set a starting position vector as the origin, having

[start]
position = [0,0,0]

fail to be read by toml::get<std::vector<double>>(start_table.at("position")) is quite frustrating. I appreciate that doing implicit lossy conversions (1.2 as an int for example) might be an implementation choice, but the inability to get 0 as a double seems to be a bit arbitrary. If it is technically possible but not something you feel the need to implement, then I might have a look.

Thanks for the great library!

luketpickering avatar Oct 20 '20 15:10 luketpickering

I basically agree with your point, it would be more useful if it can convert int64_t into float and vice versa. But there is a reason why it is not supported.

When we specify a type that does not require any type conversion, it returns a reference (like int64_t&) that enables us to modify the content through it.

int64_t& x = toml::find<int64_t>(input, "x");
x = 42; // overwrite "x" in `input`

But, it is not possible to bind int64_t as a reference to other type, like double&. double is one of the types that is contained in the internal storage of toml::value and does not require type conversion (if the toml::value contains Float value). So if double is specified as a template argument of toml::get, it should returns double&, for the sake of consistency. Here, if the value actually contains int64_t, we cannot bind it to double& and the return type must be double. The problem is that we cannot know the actual contained type before parsing a file. If we want to support conversion, the return type of toml::get (whether it is a reference or a value) should be determined after checking what value is contained, that means that the type should be changed at runtime, and it is impossible.

So the available options are

  • returning a value by copy. conversion via toml::get becomes handy, but modification is impossible. (breaking change)
  • returning a value by reference. conversion via toml::get has restriction, but modification is possible. (current implementation)
  • returning a wrapper type that automatically casts a value in assignment operator, and making the code complicated. (breaking change)
  • add a totally new function, that might be named as toml::as<T>, that always returns a value instead of reference. (minor update)

I think the most feasible option is the last one.

ToruNiina avatar Oct 20 '20 16:10 ToruNiina

Understood, I hadn't appreciated the reference problem. To forge ahead, I worked around it in my code with a simple toml::find wrapper template that if the return type template std::is_floating_point<T>::value is true, then it uses a specialization that checks at runtime if the parsed type is_integer() with the toml::value methods and if it is does the conversion.

Your proposed solution sounds perfect though, thank you for taking the time to read and think about my question!

luketpickering avatar Oct 22 '20 21:10 luketpickering

Could it give a warning if a key exists but with wrong type?

xgdgsc avatar Oct 14 '21 06:10 xgdgsc