Here's a class definition as an example.
#include <string>
#include <map>
template <class T>
class Collection
{
private:
std::map<std::string, T> data;
public:
Collection() {}
Collection(std::map<std::string, T> d)
{
data = d;
}
};
This works fine when initializing Collections with ints, chars, and even vector templated types. However, when initializing a one with a string and calling the second overloaded constructor, like:
Collection<std::string> col({
{ "key", "value" }
});
It does not compile, and throws this exit error:
main.cpp:24:22: error: call to constructor of 'Collection<std::__cxx11::string>'
(aka 'Collection<basic_string<char> >') is ambiguous
Collection<string> col({
^ ~
main.cpp:8:7: note: candidate constructor (the implicit move constructor)
class Collection
^
main.cpp:8:7: note: candidate constructor (the implicit copy constructor)
main.cpp:16:3: note: candidate constructor
Collection(map<string, T> d)
^
The strange thing is, while this notation is fine with other types, and this breaks, this notation works for string:
Collection<std::string> col(std::map<std::string, std::string>({
{ "key", "value" }
}));
What's going on here?
Collection<std::string> col{{ { "key", "value" } }};examplestd::moveand an initializer list instead:Collection(std::map<std::string, T> d) : data(std::move(d)) { }. Doing so would avoid a pointless default initialization and copy-assignmentstd::move()so as to copy only once (as shown by @alter igel). I expect that's omitted from the question as it's irrelevant to the ambiguity issue.