Loki-Astari / ThorsMongo

C++ MongoDB API and BSON/JSON Serialization library
GNU General Public License v3.0
316 stars 72 forks source link

Std:array not working on header only version #65

Closed gladijos closed 3 years ago

gladijos commented 4 years ago

Describe the bug

A minimal compilable example of that features the bug.

#include <fstream>
#include "ThorSerialize/JsonThor.h"
#include "ThorSerialize/SerUtil.h"

struct TestClass
{
  std::array<uint8_t, 16> testField;
};

ThorsAnvil_MakeTrait(TestClass, testField);

using ThorsAnvil::Serialize::jsonExport;
using ThorsAnvil::Serialize::jsonImport;
int main(int argc, char* argv[])
{
  std::fstream fileStream;
  TestClass entity;
  fileStream >> jsonImport(entity);
  fileStream << jsonExport(entity);
  return 0;
}

A description of how to build and run the code. I use header-only version

g++ -std=c++14 -I/usr/local/include  main.cpp

Expected behavior

compile OK

Environment:

Additional context

I got compile-time error

base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp: In instantiation of ‘class ThorsAnvil::Serialize::SerializerForBlock<(ThorsAnvil::Serialize::TraitType)0, unsigned char>’: base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:807:48: required from ‘void ThorsAnvil::Serialize::Serializer::print(const T&) [with T = unsigned char]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/SerUtil.h:105:13: required from ‘void ThorsAnvil::Serialize::PutValueType<V, type>::putValue(const V&) [with V = unsigned char; ThorsAnvil::Serialize::TraitType type = (ThorsAnvil::Serialize::TraitType)0]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/SerUtil.h:190:17: required from ‘void ThorsAnvil::Serialize::ContainerMemberExtractorEmplacer<C, V>::operator()(ThorsAnvil::Serialize::PrinterInterface&, const C&) const [with C = std::array<unsigned char, 16>; V = unsigned char]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:801:11: required from ‘void ThorsAnvil::Serialize::Serializer::printMembers(const T&, Action) [with T = std::array<unsigned char, 16>; Action = ThorsAnvil::Serialize::ContainerMemberExtractorEmplacer<std::array<unsigned char, 16>, unsigned char>]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:839:5: required from ‘void ThorsAnvil::Serialize::Serializer::printObjectMembers(const T&) [with T = std::array<unsigned char, 16>]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:729:13: [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ] base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:795:5: required from ‘void ThorsAnvil::Serialize::Serializer::printMembers(const T&, const std::tuple<_Elements ...>&) [with T = TestClass; Members = {std::pair<const char, std::array<unsigned char, 16> TestClass::>}]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:839:5: required from ‘void ThorsAnvil::Serialize::Serializer::printObjectMembers(const T&) [with T = TestClass]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:577:13: required from ‘void ThorsAnvil::Serialize::SerializerForBlock<traitType, T>::printMembers() [with ThorsAnvil::Serialize::TraitType traitType = (ThorsAnvil::Serialize::TraitType)3; T = TestClass]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:808:5: required from ‘void ThorsAnvil::Serialize::Serializer::print(const T&) [with T = TestClass]’ base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Exporter.h:35:17: required from ‘std::ostream& ThorsAnvil::Serialize::operator<<(std::ostream&, const ThorsAnvil::Serialize::Exporter<ThorsAnvil::Serialize::Json, TestClass>&)’ ./main.cpp:22:38: required from here base-path-to-3rd-party-libraries/ThorsSerializer/ThorSerialize/Serialize.tpp:555:5: error: static assertion failed: Invalid Serialize Trait

gladijos commented 4 years ago

Possible this issue come from using uint8_t type, with int type compiles fine

ripe909 commented 4 years ago

There is no support for char or uint8_t, so that is probably the issue. I did add some customizations to my code that support uint8_t as an int and the array of uint8_t does work.

Loki-Astari commented 4 years ago

The supported basic types are defined here:

https://github.com/Loki-Astari/ThorsSerializer/blob/master/src/Serialize/Traits.h#L436

Not sure how to support type aliases. Or if using traits on type alieases would work consistently that is something I would need to test a bit.

ripe909 commented 4 years ago

Since I would never use char, only uint8, I added all of the appropriate functions to treat it like an int. You can just search for one of the other types like 'short' to find all the places to add support.

It worked like any other type, except I had to cast it when putting it into the stream to make sure it wasn't treated as a char in the Printer override:

HEADER_ONLY_INCLUDE void JsonPrinter::addValue(uint8_t value)
{ output << PrefixValue(config.characteristics, state.size(), state.back()) << (unsigned int) value;}

I also did the same for int8_t, and I expected problems with the signedness casting to int, but it worked, but that may be implementation specific

Loki-Astari commented 4 years ago

@ripe909 The only issue here are:

  1. uint8 is not a C++ type.
  2. Though uint8_t is but only in the std namespace (so std::uint8_t).

I am more than happy to accept a pull request with these modifications (and appropriate unit tests).

ripe909 commented 4 years ago

I will try and create a clean PR.

It would probably make more sense to use char type rather than the uint8_t alias. I just use uint8_t to make the intention clear, but it is just an alias for unsigned char in my toolchain.

Maybe a directive that must be set to enable the use of chars as ints would make it clearer?