#7364 closed Bugs (duplicate)
ambiguity error constructing std::vector from assign::list_of
Reported by: | Eric Niebler | Owned by: | James E. King, III |
---|---|---|---|
Milestone: | Boost 1.69 | Component: | assign |
Version: | Boost 1.53.0 | Severity: | Problem |
Keywords: | Cc: |
Description
The problem is due to the addition of rvalue-reference container constructors. The following fails to compile with vc10:
#include <vector> #include <boost/assign/list_of.hpp> int main() { std::vector<int> i(boost::assign::list_of(1)); }
The error is:
1>c:\boost\org\trunk\libs\proto\scratch\main.cpp(6): error C2668: 'std::vector<_Ty>::vector' : ambiguous call to overloaded function 1> with 1> [ 1> _Ty=int 1> ] 1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(593): could be 'std::vector<_Ty>::vector(std::vector<_Ty> &&)' 1> with 1> [ 1> _Ty=int 1> ] 1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(515): or 'std::vector<_Ty>::vector(unsigned int)' 1> with 1> [ 1> _Ty=int 1> ] 1> while trying to match the argument list '(boost::assign_detail::generic_list<T>)' 1> with 1> [ 1> T=int 1> ] 1> 1>Build FAILED.
Change History (17)
follow-up: 6 comment:1 by , 10 years ago
follow-up: 3 comment:2 by , 10 years ago
Below is an implementation of list_of
that addresses the issue for C++11 compilers.
#include <iostream> #include <iterator> #include <algorithm> #include <deque> #include <vector> #include <utility> #include <type_traits> template<typename T> using uncvref = typename std::remove_cv<typename std::remove_reference<T>::type>::type; template<typename T> struct generic_list; template<typename T> generic_list<uncvref<T>> list_of(T && t); template<typename T> struct generic_list { private: std::deque<T> values; friend generic_list<T> list_of<>(T && t); friend generic_list<T> list_of<>(T & t); friend generic_list<T> list_of<>(T const & t); generic_list() = default; public: generic_list(generic_list &&) = default; generic_list(generic_list const &) = delete; generic_list &operator=(generic_list &&) = delete; generic_list &operator=(generic_list const &) = delete; template<typename U> generic_list & operator()(U && t) noexcept(noexcept(values.push_back(static_cast<U &&>(t)))) { values.push_back(static_cast<U &&>(t)); return *this; } template<typename Container, typename = decltype(Container(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end())))> operator Container() noexcept(noexcept(Container(Container(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()))))) { return Container(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end())); } }; template<typename T> inline generic_list<uncvref<T>> list_of(T && t) { return std::move(generic_list<uncvref<T>>()(static_cast<T &&>(t))); } struct moveable { moveable() = default; moveable(moveable &&) = default; moveable(moveable const &) = delete; moveable &operator=(moveable &&) = default; moveable &operator=(moveable const &) = delete; }; int main() { std::vector<int> i(list_of(1)); std::copy(i.begin(), i.end(), std::ostream_iterator<int>(std::cout, "\n")); std::vector<moveable> j = list_of(moveable())(moveable()); }
The trick to fixing the ambiguity error is the defaulted template parameter on operator Container
that only allows the conversion if the container can be constructed from a pair of iterators.
HTH.
comment:3 by , 10 years ago
Replying to eric_niebler:
Below is an implementation of
list_of
that addresses the issue for C++11 compilers.#include <iostream> #include <iterator> #include <algorithm> #include <deque> #include <vector> #include <utility> #include <type_traits> template<typename T> using uncvref = typename std::remove_cv<typename std::remove_reference<T>::type>::type; template<typename T> struct generic_list; template<typename T> generic_list<uncvref<T>> list_of(T && t); template<typename T> struct generic_list { private: std::deque<T> values; friend generic_list<T> list_of<>(T && t); friend generic_list<T> list_of<>(T & t); friend generic_list<T> list_of<>(T const & t); generic_list() = default; public: generic_list(generic_list &&) = default; generic_list(generic_list const &) = delete; generic_list &operator=(generic_list &&) = delete; generic_list &operator=(generic_list const &) = delete; template<typename U> generic_list & operator()(U && t) noexcept(noexcept(values.push_back(static_cast<U &&>(t)))) { values.push_back(static_cast<U &&>(t)); return *this; } template<typename Container, typename = decltype(Container(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end())))> operator Container() noexcept(noexcept(Container(Container(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()))))) { return Container(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end())); } }; template<typename T> inline generic_list<uncvref<T>> list_of(T && t) { return std::move(generic_list<uncvref<T>>()(static_cast<T &&>(t))); } struct moveable { moveable() = default; moveable(moveable &&) = default; moveable(moveable const &) = delete; moveable &operator=(moveable &&) = default; moveable &operator=(moveable const &) = delete; }; int main() { std::vector<int> i(list_of(1)); std::copy(i.begin(), i.end(), std::ostream_iterator<int>(std::cout, "\n")); std::vector<moveable> j = list_of(moveable())(moveable()); }The trick to fixing the ambiguity error is the defaulted template parameter on
operator Container
that only allows the conversion if the container can be constructed from a pair of iterators.HTH.
I must point out the fix you posted does not compile in Visual Studio 2012. The templated using syntax and the = default and = delete modifiers are not implemented in VS2012
comment:5 by , 10 years ago
To be fair to Thorsten, I think this is impossible to fix in C++98. At least, I wasn't able to think of a way.
comment:6 by , 9 years ago
Replying to zadirion@…:
Adding a to_container(dummy) call on the second list_of fixes the issue
or more succinctly convert_to_container< container_type >().
comment:8 by , 9 years ago
Hi Guys
is there any update on this issue? any fix for VS2012?
Thanks Ahmed
comment:9 by , 8 years ago
Hi Guys,
Is there any update on this issue? Any fix for VS2013?
Thanks, Abhishek D
comment:10 by , 8 years ago
My patch (assign_cxx0x.patch) in #5419 fixes this problem on clang and gcc. I've not tested with VS, but I believe it works fine on VS 2013.
comment:11 by , 7 years ago
Any chance we can get this fix into boost 1.60? I found it solves the issue as well.
comment:13 by , 5 years ago
Had to use workaround
using namespace boost::assign; std::vector<int> data; data += 1,2,3;
comment:14 by , 4 years ago
Owner: | changed from | to
---|
comment:16 by , 4 years ago
Milestone: | To Be Determined → Boost 1.69 |
---|---|
Version: | Boost Development Trunk → Boost 1.53.0 |
Ok, since my report was closed as a duplicate, I'll be letting people know here that a temporary fix for this is the following:
Adding a to_container(dummy) call on the second list_of fixes the issue, where dummy is a dummy object of the same type as the container.