Mysterious User
Mysterious User

Reputation: 308

How to partially specialize std::unordered_map as a member of my templated class?

I can't seem to understand why this does not work:

#include <unordered_map>
#include <vector>

template<typename T>
struct Bar {
    Bar(const T &t) : x{t} {}
    T x;
};

template<typename T>
struct Foo {
    std::unordered_map<T, Bar<T>> u;

    Foo(const std::vector<T> &v) {
        for (const T &i : v)
            u[i] = Bar(i);
    }    
};

int main() {
    Foo<int> f({1, 2, 3});
}

Try it here

What I want is to have an instance of Foo that contains an unordered_map that maps objects of type T to objects of type Bar. The error message is unfortunately not as helpful as I wish: error: no matching function for call to 'Bar<int>::Bar()'

What is happening here? How do I solve this problem?

Upvotes: 1

Views: 127

Answers (1)

Mysterious User
Mysterious User

Reputation: 308

As @songyuanyao has very cleverly noticed, the problem was that std::unordered_map::operator[] returns a reference to the mapped type, which requires a constructor that takes no arguments. Using std::unordered_map::insert solves this without requiring the introduction of such constructor in bar:

#include <unordered_map>
#include <vector>

template<typename T>
struct Bar {
    Bar(const T &t) : x{t} {}
    T x;
};

template<typename T>
struct Foo {
    std::unordered_map<T, Bar<T>> u;

    Foo(const std::vector<T> &v) {
        for (const T &i : v)
            u.insert({i, Bar<T>(i)});
    }    
};

int main() {
    Foo<int> f({1, 2, 3});
}

Try it here

Upvotes: 2

Related Questions