0

I making a custom map class (kc::map) that extends std::map, and I want to add operator*. operator+/operator+= works, but operator* doesn't works:

template<typename K, typename V> class map : public std::map<K, V>
{
    public:
        using std::map<K, V>::map;
        map<K, V> get_value()
        {
            return *this;
        }
        map<K, V> operator+(map<K, V> m)
        {
            map<K, V> output = get_value();
            output.insert(m.begin(), m.end());
            return output;
        }
        map<K, V> operator*(int x)
        {
            map<K, V> md = get_value();
            map<K, V> output = md;
            for (int i = 0; i < x - 1; i++)
            {
                output += md;
            }
            return output;
        }
        map<K, V> operator+=(map<K, V> m)
        {
            *this = *this + m;
            return *this;
        }
        map<K, V> operator*=(int x)
        {
            *this = *this * x;
            return *this;
        }
};

Edit

Actually, the problem is in operator+. Actually, I tested operator+ in the one-element case.

  • First of all I wouldn't make this operations in a derived map (inheritance from stl type isn't recommended anyway), but standalone functions. I also would not pass x as int, but as const T& (so you multiply values in the map with an x of their own type). The get_values is not necessary and in operator* you should iterate over key,value pairs and only update the values (have a look at structured bindings to do this nicely) – Pepijn Kramer Jan 18 '22 at 06:24
  • 3
    What do you mean by "doesn't work"? Fails to compile? If so, what's the error message? Compiles but produces unexpected output? If so please edit the question to include a minimal reproducible example demonstrating the calling code and what you expected to happen instead. – Nathan Pierson Jan 18 '22 at 06:24
  • One of the (multiple) problems with your code is that you pass your map by value. I guess that is not what you intended to do. – Dmitry Kuzminov Jan 18 '22 at 06:30
  • This is a link to a question about STL and inheritance, you might find it interesting : https://stackoverflow.com/questions/1647298/why-dont-stl-containers-have-virtual-destructors – Pepijn Kramer Jan 18 '22 at 06:42
  • 1
    Are inserting a map into itself when "multiplying", i.e. map the same same keys to the same values again and again? It works, you just can't notice any difference. – bipll Jan 18 '22 at 06:44
  • Your `+` ignores keys that are common in `this` and `m`. I'm wouldn't call that `operator +`, I'd call it `intersection`, or `operator |`. Because of that your `*` is a long-winded way of copying. – Caleth Jan 21 '22 at 16:27
  • Offtopic: `I making a custom map class (kc::map) that extends std::map` - don't do that! I know that beginners believes that OOP is about inheriting after everything, but this bad approach. Try use map as filed of your class, it may look like more work, but you will avoid lots of strange problems. Please describe what your class suppose to be used for, then we will provide more detailed and solid reasons to drop this inheritance. – Marek R Feb 13 '22 at 23:01

2 Answers2

0

Example for multiplication :

#include <map>
#include <iostream>

template<typename key_t, typename value_t>
auto operator*(std::map<key_t, value_t> copy_of_map, const value_t& factor)
{
    for (auto& [key, value] : copy_of_map)         // range based for loop, loops over all key/value pairs (the [key,value] is a structured binding)
    {
        value *= factor;                    // value is reference so we can change it.
    }

    return copy_of_map;
}


int main()
{
    std::map<int, int> map{ {1,1},{2,2},{3,3},{4,4} };
    auto multiplied_map = (map * 4);

    for (const auto& [key, value] : multiplied_map)
    {
        std::cout << "key = " << key << ", value = " << value << "\n";
    }

    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
0

You need a sensible +.

If I were "adding maps" I'd want a value for each key in the intersection, adding the values that have intersecting keys.

map<K, V> operator+(map<K, V> m) const
{
    for (const auto & [key, value] : *this) {
        m[key] += value;
    }
    return m;
}

Whilst you can write * in terms of repeated addition, I wouldn't. That also allows you to multiply by V, not int.

map<K, V> operator*(V x)
{
    map<K, V> output = *this;
    for (auto & value : output | std::ranges::views::values) {
        value *= x;
    }
    return output;
}
Caleth
  • 52,200
  • 2
  • 44
  • 75