Search code examples
c++c++11stlshared-ptr

call const overloaded function with std::map of std::shared_ptr


I am trying to call a const overload function

void process(std::map<std::string,std::shared_ptr<const Data_Struct>>);

with data I generate. Because I generate the data, I use a non-const version

std::map<std::string,std::shared_ptr<Data_Struct>> my_data;

When I try to call my function with

process(my_data);

I get the error:

error C2664: 'void process(std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>)' : cannot convert argument 1 from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'

I have tried a variety of casting variations but all fail to do the job. Any help is appreciated.

Here is my test code with the casting variants and associated error codes (I am using Visual C++ community edition 2013):

struct Data_Struct
{
    int a;
    std::string b;
};

void process(std::map<std::string,std::shared_ptr<const Data_Struct>>);

void calling_function() {
    std::map<std::string,std::shared_ptr<Data_Struct>> my_data;
    my_data.emplace("test",std::shared_ptr<Data_Struct>(new Data_Struct)).first->second->a = 2;
    process(my_data);
        // error C2664: 'void process(std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>)' : cannot convert argument 1 from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
    process(std::map<std::string,std::shared_ptr<const Data_Struct>>(my_data));
        // error C2440: '<function-style-cast>' : cannot convert from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
    process((std::map<std::string,std::shared_ptr<const Data_Struct>>)my_data);
        // error C2440: 'type cast' : cannot convert from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
    process(static_cast<std::map<std::string,std::shared_ptr<const Data_Struct>>>(my_data));
        // error C2440: 'static_cast' : cannot convert from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
    process(reinterpret_cast<std::map<std::string,std::shared_ptr<const Data_Struct>>>(my_data));
        // error C2440: 'reinterpret_cast' : cannot convert from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
    process(const_cast<std::map<std::string,std::shared_ptr<const Data_Struct>>>(my_data));
        // error C2440: 'const_cast' : cannot convert from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<const Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
    process(std::static_pointer_cast<std::map<std::string,std::shared_ptr<const Data_Struct>>>(my_data));
        // error C2784: 'std::shared_ptr<_Ty> std::static_pointer_cast(const std::shared_ptr<_Ty2> &) throw()' : could not deduce template argument for 'const std::shared_ptr<_Ty2> &' from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
    process(std::const_pointer_cast<std::map<std::string,std::shared_ptr<const Data_Struct>>>(my_data));
        // error C2784: 'std::shared_ptr<_Ty> std::const_pointer_cast(const std::shared_ptr<_Ty2> &) throw()' : could not deduce template argument for 'const std::shared_ptr<_Ty2> &' from 'std::map<std::string,std::shared_ptr<Data_Struct>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>'
}

void process(std::map<std::string,std::shared_ptr<const Data_Struct>> data) {
    for(auto &d : data)
        std::cout << d.first << std::endl;
}

Solution

  • The function process() takes its parameter by value. This means that when it's called a copy of the map is taken, processed and then discarded. I don't know if that's your intention. Assuming it is, what you need is a conversion function:

    #include <iostream>
    #include <string>
    #include <map>
    #include <memory>
    
    
    struct Data_Struct
    {
        int a;
        std::string b;
    };
    
    void process(std::map<std::string,std::shared_ptr<const Data_Struct>>);
    
    std::map<std::string,std::shared_ptr<const Data_Struct>>
    convert_map(const std::map<std::string,std::shared_ptr<Data_Struct>>& source)
    {
        std::map<std::string,std::shared_ptr<const Data_Struct>> ret;
        for(const auto& item : source) {
            ret.emplace(item.first, item.second);
        }
        return ret;
    }
    
    void process(std::map<std::string,std::shared_ptr<const Data_Struct>> data) {
        for(auto &d : data)
            std::cout << d.first << std::endl;
    }
    
    void calling_function() {
        std::map<std::string,std::shared_ptr<Data_Struct>> my_data;
        my_data.emplace("test",std::shared_ptr<Data_Struct>(new Data_Struct)).first->second->a = 2;
        process(convert_map(my_data));
    }
    
    
    using namespace std;
    
    int main()
    {
        calling_function();
    
        return 0;
    }