c++visual-c++c++17stdset

Issue with std::set::insert using a custom comparator


I wrote a small struct used to sort dependencies between projects (it could be used to sort anything really, the interface used is just a std::string) in a container/solution.

The dependencies are defined and fed from a json object (parsing is done using boost::json).

Example dependencies:

"container_dependency_tree": {
    "abc": ["def","hello","world"],
    "def": ["xyz","x","y"],
    "xyz": [],
},

Header:

#pragma once

#include <boost/json.hpp>
#include <map>
#include <string>
#include <vector>
#include <set>

namespace tmake {

    struct container_dependency_tree_t {
    private:

        std::map<std::string, std::vector<std::string>>
            m_flat;

        bool
            m_compare(const std::string& lhs, const std::string& rhs) const;//returns true if lhs depends on rhs

        std::set<std::string, decltype(&m_compare)>
            m_sorted = decltype(m_sorted)(&container_dependency_tree_t::m_compare);

    public:

        container_dependency_tree_t() {}

        container_dependency_tree_t(const boost::json::object& container_dependency_tree);

    public:

        const decltype(m_flat)&
            flat() const;

        const decltype(m_sorted)&
            sorted() const;
    };
}

Implementation:

#include <tmake/container_dependency_tree_t.h>

namespace tmake {

    container_dependency_tree_t::container_dependency_tree_t(const boost::json::object& container_dependency_tree) {
        for (const auto& kv : container_dependency_tree) {
            std::vector<std::string> dependencies;
            const boost::json::array& dd = kv.value().as_array();
            for (const auto& d : dd) {
                dependencies.push_back(d.as_string().c_str());
            }
            m_flat.emplace(kv.key(), dependencies);
        }

        for (const auto& f : m_flat) {
            m_sorted.insert(f.first);//***ISSUE HERE***
        }
    }

    bool container_dependency_tree_t::m_compare(const std::string& lhs, const std::string& rhs) const {
        auto find = m_flat.find(lhs);
        if (find == m_flat.end())
            return false;

        for (const auto& dependency : find->second) {
            if (rhs == dependency || m_compare(dependency, rhs)) {
                return true;
            }
        }

        return false;
    }

    const decltype(container_dependency_tree_t::m_flat)& container_dependency_tree_t::flat() const {
        return m_flat;
    }

    const decltype(container_dependency_tree_t::m_sorted)& container_dependency_tree_t::sorted() const {
        return m_sorted;
    }
}

The issue is with the instruction m_sorted.insert(f.first);.

I get thrown some compiler mumbo-jumbo that I dont understand - the error is somewhere within the STL implementation files (MSVC xutility(1372,19): error C2064: le terme ne correspond pas à une fonction qui prend 2 arguments).

What am I doing wrong ?


Solution

  • The error comes from you trying to use a class member function which has an implicit first parameter that is the this pointer. Since you need access to m_flat you need to wrap up the object to use with the function to call so that the set gets a function object that takes just two const string& parameters. You can do that like

    struct container_dependency_tree_t {
    private:
    
        std::map<std::string, std::vector<std::string>>
            m_flat;
    
        bool 
            m_compare(const std::string& lhs, const std::string& rhs) const;//returns true if lhs depends on rhs
    
        std::set<std::string, std::function<bool(const std::string&, const std::string&)>>
            m_sorted = decltype(m_sorted)([this](const std::string& lhs, const std::string& rhs)
                       { 
                           return this->m_compare(lhs, rhs); 
                       });
    
    public:
    
        container_dependency_tree_t() {}
    
        container_dependency_tree_t(const boost::json::object& container_dependency_tree);
    
    public:
    
        const decltype(m_flat)&
            flat() const;
    
        const decltype(m_sorted)&
            sorted() const;
    };