Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Overloading method to accept const or non-const parameter without duplicating code

I have a project where I’m putting objects in an unordered_map that can logically chain together with other objects in the map. To represent this chain, I store a reference to the next object in the chain’s map key, so I end up with something resembling a linked list within the map:

class Foo
{
    int *next;
    // other fields, methods, etc.
};
std::unordered_map<int, Foo> foos;

I’ve added a helper method that follows the linked list for an object and returns pointers to the following objects in a vector:

class Foo
{
    int *next;

    std::vector<Foo *> following(std::unordered_map<int, Foo> &foos) const
    {
        std::vector<Foo *> result;
        const Foo *current = this;
        while (current->next)
        {
            auto nextIt = foos.find(*current->next);
            if (nextIt == foos.end()) break;

            result.push_back(&nextIt->second);
            current = &nextIt->second;
        }
        return result;
    }

I also want to have a version of this helper that works on a const reference to the map and returns const pointers, i.e. std::vector<const Foo *> following(const std::unordered_map<int, Foo> &foos) const. I can of course create this just by duplicating the code, but is there a way to achieve this without duplication through templating or something similar?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Yes you can do this with a little template hackery.

template <typename K>
auto following(K &foos) const
{
    using elem = std::remove_reference_t<decltype((foos.begin()->second))>;
    std::vector<elem *> result;

    const Foo *current = this;
    while (current->next)
    {
        auto nextIt = foos.find(*current->next);
        if (nextIt == foos.end()) break;
        result.push_back(&nextIt->second);
        current = &nextIt->second;
    }

    return result;
}

If you use C++20 or newer, you can restrict the template parameter to get better error messages:

template <typename K>
requires std::is_same_v<const K, const std::unordered_map<int, Foo>>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading