[shared_ptr] Error in Constructor

Using boost 1.42, the attached fails to compile with g++:
shared_ptr_test.cpp: In instantiation of ‘Wrapper<A>’:
/usr/include/boost/smart_ptr/detail/sp_convertible.hpp:48: instantiated from
‘boost::detail::sp_convertible

On Friday 21 May 2010 20:54:25 David A. Greene wrote:
What's the rationale for the enable_if'd constructor? Is BOOST_SP_NO_SP_CONVERTIBLE an official part of the library? Apparently it is causing gcc to check all doSomething members of Action against shared_ptr
and those checks are causing instantiations of Wrapper<A>.
Urk. I just found out. The attached test does not compile with BOOST_SP_NO_SP_CONVERTIBLE because it renders shared_ptr unable to construct pointer-to-base from pointer-to-derived. Ugh. How does one satisfy the requirements of both of these tests? The first test has the requirement that types tracked by shared_ptr need not be defined in some translation units. The second has the requirement that shared_ptr be able to construct a pointer-to-base from a pointer-to-derived. -Dave

David A. Greene wrote:
On Friday 21 May 2010 20:54:25 David A. Greene wrote:
What's the rationale for the enable_if'd constructor? Is BOOST_SP_NO_SP_CONVERTIBLE an official part of the library? Apparently it is causing gcc to check all doSomething members of Action against shared_ptr
and those checks are causing instantiations of Wrapper<A>. Urk. I just found out. The attached test does not compile with BOOST_SP_NO_SP_CONVERTIBLE because it renders shared_ptr unable to construct pointer-to-base from pointer-to-derived.
I see why your original test doesn't compile, but I don't see why this one
should not. The only error I get with g++ is
testbed.cpp:33: error: operands to ?: have different types
`boost::shared_ptr<Base>' and `boost::shared_ptr<A>'
and when I insert a conversion to shared_ptr<Base> to make them the same
type, it compiles.
Defining BOOST_SP_NO_SP_CONVERTIBLE will break other cases such as
void foo( shared_ptr<Base> );
void foo( shared_ptr<int> ); // 'int' stands for an unrelated type
and then calling foo with shared_ptr<A>. A similar scenario occurs if in
your original example the functions are changed to take shared_ptr

On Saturday 22 May 2010 04:14:38 Peter Dimov wrote:
Urk. I just found out. The attached test does not compile with BOOST_SP_NO_SP_CONVERTIBLE because it renders shared_ptr unable to construct pointer-to-base from pointer-to-derived.
I see why your original test doesn't compile, but I don't see why this one should not. The only error I get with g++ is
testbed.cpp:33: error: operands to ?: have different types `boost::shared_ptr<Base>' and `boost::shared_ptr<A>'
Well, yes. Without BOOST_SP_NO_SP_CONVERTIBLE, the test does not generate that error. If the code used bare pointers the error would also not occur, so it's surprising to see it just by using a smart pointer.
and when I insert a conversion to shared_ptr<Base> to make them the same type, it compiles.
True. But again, the cast isn't needed with bare pointers.
Defining BOOST_SP_NO_SP_CONVERTIBLE will break other cases such as
void foo( shared_ptr<Base> ); void foo( shared_ptr<int> ); // 'int' stands for an unrelated type
and then calling foo with shared_ptr<A>. A similar scenario occurs if in your original example the functions are changed to take shared_ptr
and shared_ptr , respectively.
Right, because there is no exact match so conversions must be tried. I was surprised in the first test that the compiler would even bother instantiating other classes when there is an exact match to a function signature. Does the standard require the compiler to try all conversions even when there is an exact match? Ah, answered right below!
FWIW, I believe that you original example can be rejected by a compiler even with BOOST_SP_NO_SP_CONVERTIBLE defined. I don't think that the compiler is required to short-circuit overload resolution when it sees an exact match. It may well proceed to instantiate shared_ptr
in order to see whether the argument can be converted to it (even though it's clear at this point that the conversion sequence will contain a user-defined conversion).
That's really bad. It effectively means one can't easily tell when one might need the full definition of a type. I ran into this because I wanted to decouple some code defining the body of one function that takes one type from the body of another that takes a different type. In terms of the example, I didn't want changes to A to cause recompilation of functions that take a Wrapper<B>. Requiring A to be defined everywhere B is used when there happens to be a declaration of a function that takes A (as with member functions) is less than friendly behavior. It seems worth it to clarify in the standard, making it explicit that the code should compile, even without BOOST_SP_NO_SP_CONVERTIBLE. In other words, my expectation would be to have overload resolution short-circuited by exact matches. I don't think having the failed instantiation of A fall under SFINAE would work because behavior would change based on whether or not the definition of A is available. -Dave

David Greene wrote:
testbed.cpp:33: error: operands to ?: have different types `boost::shared_ptr<Base>' and `boost::shared_ptr<A>'
Well, yes. Without BOOST_SP_NO_SP_CONVERTIBLE, the test does not generate that error. If the code used bare pointers the error would also not occur, so it's surprising to see it just by using a smart pointer.
The enable_if test disables the shared_ptr<Base> to shared_ptr<A> conversion, so there is no longer any ambiguity.
That's really bad. It effectively means one can't easily tell when one might need the full definition of a type. I ran into this because I wanted to decouple some code defining the body of one function that takes one type from the body of another that takes a different type. In terms of the example, I didn't want changes to A to cause recompilation of functions that take a Wrapper<B>.
I see how that might be a problem, but I don't see a solution. Either way, someone loses. I'd probably remove the typedef typename Tag::type type in this case, as it's the only thing requiring the definition of A.

On Saturday 22 May 2010 13:12:40 Peter Dimov wrote:
That's really bad. It effectively means one can't easily tell when one might need the full definition of a type. I ran into this because I wanted to decouple some code defining the body of one function that takes one type from the body of another that takes a different type. In terms of the example, I didn't want changes to A to cause recompilation of functions that take a Wrapper<B>.
I see how that might be a problem, but I don't see a solution. Either way, someone loses. I'd probably remove the typedef typename Tag::type type in this case, as it's the only thing requiring the definition of A.
Unfortunately, in the real code the typedef is needed for some metaprogramming. I will see if I can work around it somehow. Adding the cast to the ?: solves this particular problem but the real code has a good amount of proto- and fusion-generated stuff which assumes conversions with shared_ptr work as if they were bare pointers. It's not obvious where casts are needed or what the casted-to type should be. So it seems I have to choose between making the code compile and keeping separate compilation. Not a choice but it forces one to couple the code more than should be necessary. Isn't a possible solution to amend the standard to require short-circuited overload resolution? Or would that break some other existing examples? The committee is about to finalize the new standard. Is this worth discussing at this late stage? Perhaps I will submit a comment pointing to this thread. Thanks for your help! -Dave
participants (3)
-
David A. Greene
-
David Greene
-
Peter Dimov