3

I'm using the nlohmann/json library and trying to implement serialization and deserialization for one of my structs. I'm going by this example.

This is the struct and the relevant types:

typedef std::uint32_t vertex_key;
typedef std::uint64_t edge_key;
inline edge_key get_edge_key(vertex_key v1, vertex_key v2) {
    return (std::uint64_t)v1 << 32 | (std::uint64_t)v2;  // edge 64b = (v1 32b, v2 32b)
}

struct Mcnfmq {
    unsigned int n_nodes;
    vertex_key source;
    vertex_key sink;
    unsigned int flow_value;

    std::unordered_map<edge_key, int> costs;
    std::unordered_map<edge_key, int> capacities;
    std::unordered_map<edge_key, int> minimum_quantities;

    Mcnfmq(unsigned int n_nodes, vertex_key source, vertex_key sink, unsigned int flow_value)
        : n_nodes(n_nodes), source(source), sink(sink), flow_value(flow_value) {}
};

void to_json(json& j, const Mcnfmq& instance);
void from_json(const json& j, Mcnfmq& instance);

Here are the to/from implementations:

void to_json(json& j, const Mcnfmq& instance) {
    j = json{
        {"n_nodes", instance.n_nodes},
        {"source", instance.source},
        {"sink", instance.sink},
        {"flow_value", instance.flow_value},
        {"costs", instance.costs},
        {"capacities", instance.capacities},
        {"minimum_quantities", instance.minimum_quantities},
    };
}

void from_json(const json& j, Mcnfmq& instance) {
    j.at("n_nodes").get_to(instance.n_nodes);
    j.at("source").get_to(instance.source);
    j.at("sink").get_to(instance.sink);
    j.at("flow_value").get_to(instance.flow_value);
    j.at("costs").get_to(instance.costs);
    j.at("capacities").get_to(instance.capacities);
    j.at("minimum_quantities").get_to(instance.minimum_quantities);
}

The struct Mcnfmq and functions to_json and from_json obviously reside in the same namespace (global), so that shouldn't be an issue.

This is the main file:

int main() {
    std::ifstream i("output.json");
    json j2;
    i >> j2;
    i.close();

    Mcnfmq instance2 = j2.get<Mcnfmq>(); // ERROR HERE

    return 0;
}

Full error output:

test_serialization.cpp: In function 'int main()':
test_serialization.cpp:27:38: error: no matching function for call to 'nlohmann::basic_json<>::get<Mcnfmq>()'
   27 |     Mcnfmq instance2 = j2.get<Mcnfmq>();
      |                        ~~~~~~~~~~~~~~^~
In file included from test_serialization.cpp:6:
json.hpp:20717:10: note: candidate: 'template<class ValueTypeCV, class ValueType> constexpr decltype (declval<const basic_json_t&>().get_impl<ValueType>(nlohmann::detail::priority_tag<4>{})) nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::get() const [with ValueTypeCV = ValueTypeCV; ValueType = ValueType; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer; BinaryType = std::vector<unsigned char>]'
20717 |     auto get() const noexcept(
      |          ^~~
json.hpp:20717:10: note:   template argument deduction/substitution failed:
json.hpp: In substitution of 'template<class ValueTypeCV, class ValueType> constexpr decltype (declval<const basic_json_t&>().get_impl<ValueType>(nlohmann::detail::priority_tag<4>{})) nlohmann::basic_json<>::get<ValueTypeCV, ValueType>() const [with ValueTypeCV = Mcnfmq; ValueType = Mcnfmq]':
test_serialization.cpp:27:38:   required from here
json.hpp:20719:81: error: no matching function for call to 'nlohmann::basic_json<>::get_impl<Mcnfmq>(nlohmann::detail::priority_tag<4>) const'
20719 |     -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
json.hpp:20579:15: note: candidate: 'template<class ValueType, typename std::enable_if<(nlohmann::detail::is_default_constructible<T1>::value && nlohmann::detail::has_from_json<nlohmann::basic_json<>, ValueType, void>::value), int>::type <anonymous> > ValueType nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::get_impl(nlohmann::detail::priority_tag<0>) const [with ValueType = ValueType; typename std::enable_if<(nlohmann::detail::is_default_constructible<ValueType>::value && nlohmann::detail::has_from_json<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>, ValueType>::value), int>::type <anonymous> = <anonymous>; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer; BinaryType = std::vector<unsigned char>]'
20579 |     ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
      |               ^~~~~~~~
json.hpp:20579:15: note:   template argument deduction/substitution failed:
json.hpp:20578:28: error: no type named 'type' in 'struct std::enable_if<false, int>'
20578 |                    int > = 0 >
      |                            ^
json.hpp:20621:15: note: candidate: 'template<class ValueType, typename std::enable_if<nlohmann::detail::has_non_default_from_json<nlohmann::basic_json<>, ValueType, void>::value, int>::type <anonymous> > ValueType nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::get_impl(nlohmann::detail::priority_tag<1>) const [with ValueType = ValueType; typename std::enable_if<nlohmann::detail::has_non_default_from_json<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>, ValueType>::value, int>::type <anonymous> = <anonymous>; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer; BinaryType = std::vector<unsigned char>]'
20621 |     ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
      |               ^~~~~~~~
json.hpp:20621:15: note:   template argument deduction/substitution failed:
json.hpp:20620:28: error: no type named 'type' in 'struct std::enable_if<false, int>'
20620 |                    int > = 0 >
      |                            ^
json.hpp:20646:19: note: candidate: 'template<class BasicJsonType, typename std::enable_if<nlohmann::detail::is_basic_json<BasicJsonType>::value, int>::type <anonymous> > BasicJsonType nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::get_impl(nlohmann::detail::priority_tag<2>) const [with BasicJsonType = BasicJsonType; typename std::enable_if<nlohmann::detail::is_basic_json<BasicJsonType>::value, int>::type <anonymous> = <anonymous>; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer; BinaryType = std::vector<unsigned char>]'
20646 |     BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
      |                   ^~~~~~~~
json.hpp:20646:19: note:   template argument deduction/substitution failed:
json.hpp:20645:28: error: no type named 'type' in 'struct std::enable_if<false, int>'
20645 |                    int > = 0 >
      |                            ^
json.hpp:20669:16: note: candidate: 'template<class BasicJsonType, typename std::enable_if<std::is_same<BasicJsonType, nlohmann::basic_json<> >::value, int>::type <anonymous> > nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType> nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::get_impl(nlohmann::detail::priority_tag<3>) const [with BasicJsonType = BasicJsonType; typename std::enable_if<std::is_same<BasicJsonType, nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType> >::value, int>::type <anonymous> = <anonymous>; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer; BinaryType = std::vector<unsigned char>]'
20669 |     basic_json get_impl(detail::priority_tag<3> /*unused*/) const
      |                ^~~~~~~~
json.hpp:20669:16: note:   template argument deduction/substitution failed:
json.hpp:20668:25: error: no type named 'type' in 'struct std::enable_if<false, int>'
20668 |                  int> = 0>
      |                         ^
json.hpp:20682:20: note: candidate: 'template<class PointerType, typename std::enable_if<std::is_pointer<_Tp>::value, int>::type <anonymous> > constexpr decltype (declval<const basic_json_t&>().get_ptr<PointerType>()) nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::get_impl(nlohmann::detail::priority_tag<4>) const [with PointerType = PointerType; typename std::enable_if<std::is_pointer<_Ptr>::value, int>::type <anonymous> = <anonymous>; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer; BinaryType = std::vector<unsigned char>]'
20682 |     constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
      |                    ^~~~~~~~
json.hpp:20682:20: note:   template argument deduction/substitution failed:
json.hpp:20681:25: error: no type named 'type' in 'struct std::enable_if<false, int>'
20681 |                  int> = 0>
      |                         ^
json.hpp:20758:10: note: candidate: 'template<class PointerType, typename std::enable_if<std::is_pointer<_Tp>::value, int>::type <anonymous> > decltype (declval<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::basic_json_t&>().get_ptr<PointerType>()) nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::get() [with PointerType = PointerType; typename std::enable_if<std::is_pointer<_Ptr>::value, int>::type <anonymous> = <anonymous>; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long long int; NumberUnsignedType = long long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer; BinaryType = std::vector<unsigned char>]'
20758 |     auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
      |          ^~~
json.hpp:20758:10: note:   template argument deduction/substitution failed:
json.hpp:20757:68: error: no type named 'type' in 'struct std::enable_if<false, int>'
20757 |                  std::is_pointer<PointerType>::value, int>::type = 0>
      |                                                                    ^

My questions:

  1. What are the error messages actually saying?
  2. How can this be fixed?
corazza
  • 31,222
  • 37
  • 115
  • 186

1 Answers1

3

I think the deserialization code expects a default constructor to exist. IIRC, adding a custom constructor to a struct will remove the default one. The issue is fixed if the custom constructor is removed, or a default one is added in the struct declaration explicitly (Mcnfmq() {}).

(I will of course accept someone else's answer that provides a better explanation.)

corazza
  • 31,222
  • 37
  • 115
  • 186