Home > OS >  Why is this map returning an rvalue?
Why is this map returning an rvalue?

Time:08-03

I am using the library nlohmann/json and wish to create an unordered_map of std::string to nlohmann::json.

#include <nlohmann/json.hpp>

class basic_container {
public:
    using key_type = std::string;
    using mapped_type = nlohmann::json;
    using container_type = std::unordered_map<key_type, mapped_type>;
    using reference = typename container_type::reference;
    using const_reference = typename container_type::const_reference;

    // error: cannot bind non-const lvalue reference to an rvalue
    reference at(const key_type &key) {
        return data.at(key);
    }

    // warning: returning reference to temporary
    const_reference at(const key_type &key) const {
        return data.at(key);
    }

    // error: cannot bind non-const lvalue reference to an rvalue
    reference operator[](const key_type &key) {
        return data[key];
    }

private:
    container_type data;
};

The nlohmann::json class is defined in the library similarly to the following.

template<...>
class basic_json {};

using json = basic_json<>;

I can't figure out why I'm having problems when trying to return a reference or a const reference to a nlohmann::json. The full compiler error for the error: sections within the above code is outlined below.

error: cannot bind non-const lvalue reference of type 'container::reference' {aka 'std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_json<> >&'} to an rvalue of type 'std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_json<> >'

The nicer intellisense error.

a reference of type "container::reference" (not const-qualified) cannot be initialized with a value of type "nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double, std::allocator, nlohmann::adl_serializer, std::vector<uint8_t, std::allocator<uint8_t>>>"

Appreciate any help. Thanks

Edit: The solution was to properly define the aliases. See the following.

class basic_container {
public:
    using key_type = std::string;
    using mapped_type = nlohmann::json;
    using container_type = std::unordered_map<key_type, mapped_type>;
    // using reference = typename container_type::reference;
    // using const_reference = typename container_type::const_reference;
    using reference = typename mapped_type::reference;
    using const_reference = typename mapped_type::const_reference;

    // ...
};

CodePudding user response:

Your wrappers for at(), et. al. are returning the wrong thing.

If you look up the reference for unordered_map::at(): it returns a reference to a (const) T, a.k.a. value_type, a.k.a. your mapped_type.

reference/const_reference is something completely different.

The same problem also happens with your operator[] overload.

P.S. The easiest way to avoid this confusion is to declare your return types as (const-qualified, where appropriate) auto & (in this case). Let your C compiler get it right.

  • Related