Why can I pass boost map_list_of to a function that accepts a map but not a constructor?

I am trying to build an object that takes std::map as a parameter, passing the contents of the map to it using boost map_list_of .

This gives a compilation error, however, when I try to do the same with a regular function that accepts std::map , it compiles fine!

 #include <map> #include <boost/assign.hpp> struct Blah { Blah(std::map<int, int> data) {} }; void makeBlah(std::map<int, int> data) {} int main() { Blah b(boost::assign::map_list_of(1, 2)(3, 4)); // Doesn't compile. makeBlah(boost::assign::map_list_of(1, 2)(3, 4)); // Compiles fine! } 

Compilation Error:

 error: call of overloaded 'Blah(boost::assign_detail::generic_list<std::pair<int, int> >&)' is ambiguous note: candidates are: Blah::Blah(std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >) note: Blah::Blah(const Blah&) 

What is the ambiguity, and why does this not affect the usual functoin makeBlah, which, as far as I can see, has the same signature as the Blah constructor?

And is there a better way to achieve this if you do not make the makeBlah function that will create the Blah object, since it seems to me that I will need to do?

(As an aside, I do this in unit test, using map_list_of to make creating test input more readable)

+8
c ++ constructor boost stl stdmap
source share
2 answers

map_list_of does not create a container but creates

anonymous list that can be converted to any standard container

The conversion is performed through a template user conversion operator:

  template< class Container > operator Container() const; 

So, in the context of the constructor, it cannot determine whether to convert to map<int, int> or Blah . To avoid this, you can, for example, add a stub constructor parameter:

 class Blah { public: Blah(std::map<int, int> data, int) { } }; void makeBlah(std::map<int, int> data) { } void myTest() { Blah b(boost::assign::map_list_of(1, 2)(3, 4), 0); makeBlah(boost::assign::map_list_of(1, 2)(3, 4)); } 

With makeBlah you have no such ambiguity.

Alternatively, you can take the type of the list as a constructor parameter, and then use it in Blah :

 class Blah { public: Blah(decltype(boost::assign::map_list_of(0, 0)) data) : m(data.to_container(m)) { } std::map<int, int> m; }; 
+5
source share

since the advent of C ++ 11, boost::assign became less attractive than it was.

 Blah b({{1, 2},{3, 4}}); 

must do it.

+2
source share

All Articles