Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguous call to std/boost move

Tags:

c++

boost

Came across this code which doesn't compile:

#include <boost/move/utility.hpp>
#include <utility>
#include <deque>
#include <map>
#include <vector>
#include <boost/date_time/posix_time/posix_time_types.hpp>

using namespace std;

int main() {
    typedef std::pair<int, std::deque<int>> FirstPair;
    typedef std::vector<FirstPair> VectorFirstPair;
    typedef std::pair<boost::posix_time::time_duration, VectorFirstPair> SecondPair;
    typedef std::map<boost::posix_time::time_duration, SecondPair> Map;
    Map mapInstance;
    SecondPair newElement = make_pair(boost::posix_time::not_a_date_time, VectorFirstPair());
    mapInstance.insert(make_pair(boost::posix_time::seconds(10), move(newElement))).first;
}

This fails on gcc 4.8.2 using boost 1.55 (not on boost 1.54) with the following error (ideone here):

test.cpp: In function ‘int main()’:
test.cpp:17:81: error: call of overloaded ‘move(SecondPair&)’ is ambiguous
     mapInstance.insert(make_pair(boost::posix_time::seconds(10), move(newElement))).first;
                                                                                 ^
test.cpp:17:81: note: candidates are:
In file included from /usr/include/c++/4.8/bits/stl_pair.h:59:0,
                 from /usr/include/c++/4.8/utility:70,
                 from /usr/include/boost/config/no_tr1/utility.hpp:21,
                 from /usr/include/boost/config/select_stdlib_config.hpp:37,
                 from /usr/include/boost/config.hpp:40,
                 from /usr/include/boost/move/detail/config_begin.hpp:10,
                 from /usr/include/boost/move/utility.hpp:17,
                 from test.cpp:1:
/usr/include/c++/4.8/bits/move.h:101:5: note: constexpr typename std::remove_reference< <template-parameter-1-1> >::type&& std::move(_Tp&&) [with _Tp = std::pair<boost::posix_time::time_duration, std::vector<std::pair<int, std::deque<int> > > >&; typename std::remove_reference< <template-parameter-1-1> >::type = std::pair<boost::posix_time::time_duration, std::vector<std::pair<int, std::deque<int> > > >]
     move(_Tp&& __t) noexcept
     ^
In file included from test.cpp:1:0:
/usr/include/boost/move/utility.hpp:138:55: note: typename boost::remove_reference<T>::type&& boost::move(T&&) [with T = std::pair<boost::posix_time::time_duration, std::vector<std::pair<int, std::deque<int> > > >&; typename boost::remove_reference<T>::type = std::pair<boost::posix_time::time_duration, std::vector<std::pair<int, std::deque<int> > > >]
          inline typename remove_reference<T>::type && move(T&& t) BOOST_NOEXCEPT

Shouldn't this compile? Shouldn't the using namespace clause make this unambiguous? Why is the compiler choosing boost::move as a viable candidate here?

Note that this doesn't cause any errors if I remove the boost types in the types defined (replacing them with e.g. int).

like image 290
mfontanini Avatar asked Jun 30 '15 23:06

mfontanini


2 Answers

This is because of ADL - argument dependant lookup (see this answer which is also boost related).

The problem is that the namespace boost is considered because:

§ 3.4.2 Argument-dependent name lookup

  1. ... The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). ...

Thus, because some boost-related type is a template argument of std::pair, boost::move is also considered. (imho it shouldn't because I can't figure out how to program around that ambiguity).

like image 137
WorldSEnder Avatar answered Oct 16 '22 07:10

WorldSEnder


As an alternative to explicitly qualifying std::move everywhere, you can define BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE, which just aliases boost::move to std::move. With that, your example compiles successfully.

like image 42
dhaffey Avatar answered Oct 16 '22 07:10

dhaffey