#no matching member function for call to 'get' (nlohmann)

24 messages · Page 1 of 1 (latest)

solemn mango
#

Hello, I am trying to use the nlohmann json library and I am getting an issue I really can't understand.

Basically, I have multiple custom types (struct) defined in different files but under the same namespace, they are basically defined like this:

// type1.hpp
#include "nlohmann/json.hpp"
namespace types
{
    struct type1 { /* bunch of fields */ };

    void from_json(const nlohmann::json& j, type1& t);
}
// type1.cpp
#include "type1.hpp"

void types::from_json(const nlohmann::json& j, types::type1& t) { /* implementation */ }

// type2.hpp
#include "nlohmann/json.hpp"
#include "type1.hpp" // because type2 has type1 as a field
namespace types
{
    struct type2 { /* fields */ };

    void from_json(const nlohmann::json& j, type2& t);
}

// type2.cpp
#include "type2.hpp"
void types::from_json(const nlohmann::json& j, types::type2& t) { /* implementation */ }

// some other .cpp file
#include <vector>
#include "nlohmann/json.hpp"
#include "type1.hpp"
#include "type2.hpp"

const std::vector<types::type1> getX()
{
    // assuming I retrieve the data from an API
    nlohmann::json json = nlohmann::json::parse(data);
    return json["x"].get<std::vector<types::type1>>(); // no errors
}

const std::vector<types::type2> getY()
{
    // retrieving data from API
    nlohmann::json json = nlohmann::json::parse(data);
    return json["y"].get<std::vector<types::type2>>(); // <- issue here returning  error: no matching member function for call to 'get' 
                                                       // note: candidate template ignored: substitution failure [...] no matching member function for call to 'get_impl'
}

Did anyone encounter such an issue before? Or what am I doing wrong here?

balmy galeBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

solemn mango
# swift dagger send the full error message

here it is:

[proc] Executing command: /usr/bin/cmake --build /home/usr/dev/cpp/out/build/Linux --parallel 26 --target mylibrary --
[build] [ 14%] Building CXX object CMakeFiles/mylibrary.dir/mylibrary.cpp.o
[build] /home/usr/dev/cpp/mylibrary.cpp:50:33: error: no matching member function for call to 'get'
[build]             return json["x"].get<std::vector<types::type2>>();
[build]                    ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /home/usr/dev/cpp/nlohmann/json.hpp:21046:10: note: candidate template ignored: substitution failure [with ValueTypeCV = std::vector<types::type2>, ValueType = detail::uncvref_t<std::vector<types::type2>>]: no matching member function for call to 'get_impl'
[build]     auto get() const noexcept(
[build]          ^
[build] /home/usr/dev/cpp/nlohmann/json.hpp:21087:10: note: candidate template ignored: substitution failure [with PointerType = std::vector<types::type2>]: no matching member function for call to 'get_ptr'
[build]     auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
[build]          ^                                                                 ~~~~~~~
[build] 1 error generated.
swift dagger
solemn mango
#

both type1 and type2 are defined without explicit constructors (and it works for type1, that is why it seems strange that for type2, with exactly the same constructs, it doesn't work)

swift dagger
#

nholmanjson requires that these types need to be DefaultConstructible and CopyConstructible

#

or, you can programatically check by running

type1 t1;
type1 t1Copy(t1);

type2 t2;
type2 t2Copy(t2);

and see if that compiles

#

in main

#

@solemn mango

solemn mango
#

so this is how things are defined:

// type1.hpp
#ifndef TYPES_TYPE1_HPP
#define TYPES_TYPE1_STATION_HPP

#include <iostream>
#include <string>

#include "nlohmann/json.hpp"

namespace mylibrary::types
{
    struct type1
    {
        std::string id;
        std::string url;
        std::string latitude;
        std::string longitude;
        std::string standardName;
        std::string name;
    };

    void from_json(const nlohmann::json& j, type1& s);
}

#endif

// type1.cpp
#include "type1.hpp"

void mylibrary::types::from_json(const nlohmann::json& j, mylibrary::types::type1& s)
{
    j.at("id").get_to(s.id);
    j.at("@id").get_to(s.url);
    j.at("locationX").get_to(s.latitude);
    j.at("locationY").get_to(s.longitude);
    j.at("standardname").get_to(s.standardName);
    j.at("name").get_to(s.name);
}

// type2.hpp
#ifndef TYPES_TYPE2_HPP
#define TYPES_TYPE2_HPP

#include <iostream>
#include <string>

#include "nlohmann/json.hpp"

#include "type1.hpp"

namespace mylibrary::types
{
    struct type2
    {
        std::string id;
        type1& station_info;
    };

    void from_json(const nlohmann::json& j, type2& t);
}
#endif

// type2.cpp
#include "type2.hpp"


void mylibrary::types::from_json(const nlohmann::json& j, mylibrary::types::type2& t)
{
    j.at("id").get_to(t.id);
    j.at("stationinfo").get_to(t.station_info);
}
swift dagger
#

place a raw pointer inside type2 type1* station_info_ptr and that should work

#

the way your type2 objects are accessign a foreign mysterious uncontrollable type1 value is very fragile, if someone destroys the type1 value you are referring to, and type2 tries to acces that, you get CRASHES

solemn mango
#

I'll try that

swift dagger
solemn mango
#

alright, so if I do not provide any & or *, but just type1 station_info, that works

swift dagger
solemn mango
#

@swift dagger thanks a lot btw, I would have never found that by myself

swift dagger
balmy galeBOT
#

@solemn mango Has your question been resolved? If so, type !solved :)