Skip to content
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

overwrite adl_serializer<bool, void> to change behaviour #1638

Closed
Virtual-felix opened this issue Jun 14, 2019 · 5 comments
Closed

overwrite adl_serializer<bool, void> to change behaviour #1638

Virtual-felix opened this issue Jun 14, 2019 · 5 comments

Comments

@Virtual-felix
Copy link

Virtual-felix commented Jun 14, 2019

I would like to change the behaviour of how boolean are serialized, so to_json would transform boolean to string.

I tried to do an adl_serializer specialized for bolean like this


namespace nlohmann {

template<>
struct adl_serializer<bool> {
  static void to_json(json& j, bool b) {
    j = std::string(b ? "true" : "false");
  }

  static void from_json(const json& j, bool& b) {
    b = j.template get<std::string>() == "true";
  }
};

} // namespace nlohmann

Knowing that I tried to do

b = *j.get_ptr<const json::boolean_t*>()
but it was returning a null ptr (no idea wny the bool is stocked as a string)

The fact is that this try compile and work with Clang but does not compile with GCC.
GCC output:

error: partial specialization of ‘struct nlohmann::adl_serializer<T, typename std::enable_if<std::is_same<bool, _U1>::value, void>::type>’ after instantiation of ‘struct nlohmann::adl_serializer<bool, void>’ [-fpermissive]
struct adl_serializer<T, std::enable_if_t<std::is_same<bool, T>::value>> {

But I can't understand where this instantiation happen and why it happens with GCC and not Clang.
I was wondering if there is another way to change the behaviour of a boolean serialization if it is possible.

I'm using the tag 3.5 of the library.

@nickaein
Copy link
Contributor

Just as a reference, I tried your code on VS 2019,

#include <iostream>
#include "json.hpp"

namespace nlohmann {
    template<>
    struct adl_serializer<bool> {
        static void to_json(json& j, bool b) {
            j = std::string(b ? "true" : "false");
        }

        static void from_json(const json& j, bool& b) {
            b = j.template get<std::string>() == "true";
        }
    };
} // namespace nlohmann

int main()
{
    nlohmann::json all;

    all["hello"] = true;
    all["bye"] = false;

    std::cout << all.dump() << std::endl;
}

It compiles without any errors/warnings and gives the below output as expected:

{"bye":"false","hello":"true"}

@Virtual-felix
Copy link
Author

Is you VS 2019 using CLang ? On my side it does compile with Clang and work as expected, but does not compile with GCC 6.4

@nickaein
Copy link
Contributor

Sorry for not being clear. I tested the code with native msvc compiler.

I've reproduced the error on GCC here which says:

prog.cc:20849:12: error: specialization of 'nlohmann::adl_serializer<bool, void>' after instantiation
     struct adl_serializer<bool, void> {
            ^~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:20849:12: error: redefinition of 'struct nlohmann::adl_serializer<bool, void>'
prog.cc:2170:8: note: previous definition of 'struct nlohmann::adl_serializer<bool, void>'
 struct adl_serializer
        ^~~~~~~~~~~~~~

Are you getting the same error?

I wonder if it has anything to do with the fact that the library has provided from_json implementation for bool type:

void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)

But as you stated, this error doesn't happen on Clang (and msvc). This is either a compiler bug (unlikely) or some behavior that the Standard left the choice up to the compiler implementers (like this one).

@Virtual-felix
Copy link
Author

Are you getting the same error?
Yes

I found another way to do what I wanted without having to write boolean as string. I will close this issue assuming it is a difference of behavior between the compiler, but it may hide an error I guess.

@samsaga2
Copy link

samsaga2 commented Jul 7, 2020

Sorry for reopen this issue.

But I have exactly the same problem. GCC & C++17 & adl_serializer gives me a redefinition error. There is something wrong in the library. The same code works correctly with clang, but that is only because it manages the problem differently.

I have fixed the compiler error resorting the includes. If you put the json header in the first place, this error disappears. There is some strange problem in the adl_serializer declaration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants