cereal
cereal copied to clipboard
Ambiguous overload of JSONOutputArchive::saveValue() if int32_t is long
I'm running Cereal 1.2.2 on an NXP Kinetis K64 microcontroller (Cortex-M4) using Kinetis Design Studio 3 and KSDK v2.1. I've got it working great; I'm using it to parse and emit commands and responses for a JSON-formatted protocol.
I've found that there are only two modifications I have to make to Cereal to get it to work in my build and execution environment. One involves the chunk allocator, which I'll save for a different thread. The other involves the JSONOutputArchive class, specifically the saveValue() overloads.
The crux of the issue is this: in the KDS 3 build environment, int32_t has been defined as long, and uint32_t is unsigned long. This annoys me to no end because I have to change all my print specifiers from %d to %ld to avoid warnings, etc. Of course, size_t is just unsigned int, so uint32_t and size_t are not identical types. Grr.
Anyway, here's what happens on my platform if I compile Cereal as-is (output edited for clarity):
cereal/cereal/archives/json.hpp: In member function 'void cereal::JSONOutputArchive::saveLong(T)':
cereal/cereal/archives/json.hpp:262:69: error: call of overloaded 'saveValue(int32_t)' is ambiguous
void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
cereal/cereal/archives/json.hpp:262:69: note: candidates are:
cereal/cereal/archives/json.hpp:233:12: note: void cereal::JSONOutputArchive::saveValue(bool)
void saveValue(bool b) { itsWriter.Bool(b); }
cereal/cereal/archives/json.hpp:235:12: note: void cereal::JSONOutputArchive::saveValue(int)
void saveValue(int i) { itsWriter.Int(i); }
cereal/cereal/archives/json.hpp:237:12: note: void cereal::JSONOutputArchive::saveValue(unsigned int)
void saveValue(unsigned u) { itsWriter.Uint(u); }
cereal/cereal/archives/json.hpp:243:12: note: void cereal::JSONOutputArchive::saveValue(int64_t)
void saveValue(int64_t i64) { itsWriter.Int64(i64); }
cereal/cereal/archives/json.hpp:245:12: note: void cereal::JSONOutputArchive::saveValue(uint64_t)
void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
cereal/cereal/archives/json.hpp:247:12: note: void cereal::JSONOutputArchive::saveValue(double)
void saveValue(double d) { itsWriter.Double(d); }
The method saveLong() is casting the (verified by traits) signed 32-bit value to an int32_t, and then passing that to saveValue(). But since int32_t is long, none of the saveValue() methods match, so C++ can't decide which overload to use.
My workaround for this has been to add a couple more overloads:
//! Saves a bool to the current node
void saveValue(bool b) { itsWriter.Bool(b); }
//! Saves an int to the current node
void saveValue(int i) { itsWriter.Int(i); }
//! Saves a uint to the current node
void saveValue(unsigned u) { itsWriter.Uint(u); }
++ //! Saves a long to the current node
++ void saveValue(long i) { itsWriter.Int(i); }
++ //! Saves an unsigned long to the current node
++ void saveValue(unsigned long u) { itsWriter.Uint(u); }
However, I don't think this holds up if compiling on an architecture where sizeof(int) != sizeof(long), e.g. if long is 8 bytes. I tried modifying the static_cast<> invocations in saveLong() to call int and unsigned int instead of std::int32_t and std::uint32_t, but that only fixes the internal calls to saveLong(); application calls to saveValue() will still fail if passed a long type.
So... what's the correct/best way to fix this? How can I avoid having to edit cereal/archives/json.hpp every time I import cereal into a Kinetis project? I mean, it's not a big deal to add the two extra overloads above, but editing library code is always less than ideal. Thanks.
These issues have cropped up in the past - what helps to solve it is knowing, for all of the basic types, both the sizes used by the compiler, as well as testing std::is_equal against long. We have to try and come up with a solution that is unambiguous for everyone.
Any progress on this one? I use cereal as a dependency in a publicly accessible project, and modifying vendor library is not an option there.