Domanda

I am trying to migrate some code from boost::tuple to std::tuple but I'm getting some weird errors: after I invoke using namespace std (and never boost), I expect an unqualified tie to resolve to std::tie. However, this seems to fail when the tuple contains a boost container pointer, for example.

#include <tuple>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>

#ifdef USE_STD
#define TIE std::tie
#else
#define TIE tie
#endif

typedef boost::multi_index_container<
  int,
  boost::multi_index::indexed_by<
    boost::multi_index::ordered_non_unique<
      boost::multi_index::identity<int>
    >
  >
> Set;

std::tuple< int, int* > make_i_ptr();
std::tuple< int, Set* > make_set();

int main()
{
    using namespace std;
    int i;
    int* i_ptr;
    Set* set_ptr;
    tie(i, i_ptr) = make_i_ptr();
    TIE(i, set_ptr) = make_set();
    return 0;
}

If I compile with g++ -std=c++0x -c test.cpp -DUSE_STD, all is well. However, without -D USE_STD, I get compile errors suggesting g++ tries to use boost::tuples::tie. I'm using g++ 4.8.1 and boost 1.55.0. Do you think this is a bug with boost? Or is there some spec I'm missing?

È stato utile?

Soluzione

Lookup is complicated. The problem as others have mentioned is Argument Dependent Lookup or ADL. The rules for ADL were added to allow the definition of operators in the same namespace as the types they refer to, and enabling lookup to find those operators when present. This was later extended to all other functions in the process of standarization.

The issue here is that tie(...) is a function call. The compiler will attempt regular lookup from the point of use (inside main) it will move out to the enclosing namespace. The using directive will add ::std into the lookup search when it hits the root namespace (common ancestor of ::std and ::main). At that point, since the identifier resolves to a function, ADL will kick in.

ADL adds the namespaces associated to the arguments of the function call, which in this case is boost:: (fundamental types like int have no associated namespaces). At this point the compiler sees two declarations of tie: std::tie and boost::tie, causing ambiguity.

As you already know the solution is to qualify the call to std::tie (which I would advice that you use even without this issue). Regarding the comment:

If ADL makes it resolve to boost::tie for... "my convenience" and then the compilation fails, shouldn't that be a clue to the compiler that it picked the wrong function?!

I don't know what the exact error you are getting is (I don't use boost, and I don't know what possible overloads of std::tie it contains). If the problem is indeed one of ambiguity, the problem is that the compiler cannot resolve the identifier, and cannot continue the process. At that point it stops and asks for the programmer to resolve it. If the error is that it uniquely picked boost::tie and it later failed in the assignment, it means that theres is an overload of boost::tie that is a better match than std::tie and that was selected. At a later time the assignment from std::tuple may have failed, but the compiler cannot know whether the problem was during lookup, or whether it is the assignment itself (did you intend on assigning that variable? maybe a different one?) so again it fails and tells you what the problem is.

Note that in general the process of compilation is always moving forward, the compiler does not backtrack to double guess its own decisions*. There is a set of rules, and those rules are applied at each step. If there is ambiguity, compilation stops, if not, then there is a single best candidate and this point is resolved, moving to the next. Attempting to go back to undo decisions would turn the compilation process into something painfully slow (the number of paths that could be taken would be exponential).

* As always there are some exceptions but those are just exceptions, notably during overload resolution if a template is picked as the best candidate but substitution of type arguments fail, it is discarded and the next best candidate is chosen.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top