Boost logo

Boost :

Subject: Re: [boost] Boost.Operators and make_shared
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2013-07-12 05:00:53


On Friday 12 July 2013 10:41:09 Pieter wrote:
> LS,
>
>
>
> I have noticed that using Boost.Operators has a side-effect which I can't
> explain. I am using std::make_shared as a default, however, some of the
> boost libraries I use pull in boost::make_shared as well.
>
> When using some class T2 derived from one of the boost.operators classes,
> this causes MSVC2010 to not compile when invoking make_shared<T2> as the
> compiler can no longer resolve between the two overloaded versions of
> make_shared for some reason.
>
>
>
> I am hoping that someone out can explain what is happening here. A minimal
> example is included here:
>
>
>
> #include <memory>
>
> #include <boost\operators.hpp>
>
> #include <boost\make_shared.hpp>
>
>
>
> struct T1 {};
>
> struct T2 : boost::equality_comparable<T2> {};
>
>
>
> int main( int argc, const char* argv[] )
>
> {
>
> T1 Object1;
>
> T2 Object2;
>
>
>
> using std::make_shared;
>
>
>
> std::shared_ptr<T1> Ptr1 = make_shared<T1>(Object1); // OK
>
> std::shared_ptr<T2> Ptr2 = make_shared<T2>(Object2); // error C2668:
> 'boost::make_shared' : ambiguous call to overloaded function
>
>
>
> return 1;
>
> }

This happens because of the argument dependent lookup (ADL) rules. When you
invoke unqualified make_shared, the compiler tries to find the appropriate
function. You have imported std::make_shared to the function scope, so this
one is always found. In the first call you specify Object1 of type T1 as the
argument, and T1 is in the global namespace and does not have any other
associated types with it. Therefore the imported std::make_shared is the only
function the compiler finds, so no ambiguity in this case.

In the second case you pass Object2 of type T2. T2 is also defined in the
global namespace, which has still has no make_shared functions. But the
compiler goes further and checks other types associated with T2 - in this
case, its base class boost::equality_comparable, which resides in namespace
boost. Through this base class the compiler discovers boost::make_shared,
which makes the call ambiguous.

The described behavior is expected and standard. However, I think this is a
flaw in Boost.Operators. Since these classes are intended to be base classes
for user-defined types, I think they should attempt to prevent from messing
ADL up like in this example. The solution is rather simple - all the base
classes should be enveloped into an inner namespace (e.g. boost::operators)
and then imported to namespace boost for backward compatibility. This way ADL
will look for make_shared in boost::operators and will not find it there.

I suggest you to create a ticket for Boost.Operators to implement that change.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk