Ambiguity with Smart Pointers (Boost or similar)

N

number774

I've used Boost for this example; in fact we have our own pointer
class, for historic reasons.

#include "boost\shared_ptr.hpp"

// A heirarchy of classes
class G1 {};
class G2: public G1 {};

// A method which takes a shared pointer to the base class
void f(boost::shared_ptr<G1>) {};

// A method which takes a shared pointer to some other class
void f(boost::shared_ptr<int>) {};

void main()
{
// Call a method with a shared pointer to a derived class
f(boost::shared_ptr<G2>());
}

This fails, because the compiler is unable to decide which of the two
methods is meant. Of course, to a human, it's pretty obvious which
one is meant, but there doesn't seem to be enough information at the
time for the compiler to decide. In practice I have several hundred
functions, and 50 or so classes, to get confused among, so I don't
really want to take the obvious route [declare an
f(boost::shared_ptr<G2>) ]. Is there anything I can do to the pointer
class, or even to the class inheritance, that'll help the compiler
out?

Thx
 
K

kwikius

I've used Boost for this example;  in fact we have our own pointer
class, for historic reasons.

#include "boost\shared_ptr.hpp"

// A heirarchy of classes
class G1 {};
class G2: public G1 {};

// A method which takes a shared pointer to the base class
void f(boost::shared_ptr<G1>) {};

// A method which takes a shared pointer to some other class
void f(boost::shared_ptr<int>) {};

void main()
{
        // Call a method with a shared pointer to a derived class
        f(boost::shared_ptr<G2>());

}

This fails, because the compiler is unable to decide which of the two
methods is meant.  Of course, to a human, it's pretty obvious which
one is meant, but there doesn't seem to be enough information at the
time for the compiler to decide.  In practice I have several hundred
functions, and 50 or so classes, to get confused among, so I don't
really want to take the obvious route [declare an
f(boost::shared_ptr<G2>) ].  Is there anything I can do to the pointer
class, or even to the class inheritance, that'll help the compiler
out?

Thx

I don't use boost::shared_ptr, but I am surprised if it cant
discriminate the above case, though maybe this is the result of an old
compiler, which may mean it cant use some facilities.

Hint! use some SFINAE, in combination with std::tr1 type_traits, e.g
is_base_of etc, but as I said a good smart pointer should easily
handle this case automatically.

regards
Andy Little
 
N

number774

I don't use boost::shared_ptr, but I am surprised if it cant
discriminate the above case, though maybe this is the result of an old
compiler, which may mean it cant use some facilities.

Fails with MS VC 2005 AND Gcc 4.01 on an Apple...
Hint! use some SFINAE, in combination with std::tr1 type_traits, e.g
is_base_of etc, but as I said a good smart pointer should easily
handle this case automatically.

If you know a better smart pointer, please let me know :) .
Meanwhile, I'll keep playing. is_base_of isn't in my copy of the
standard [2003, 2nd ed] but there are web refs to it in Boost which
I'll read.

Thanks
 
K

kwikius

Fails with MS VC 2005 AND Gcc 4.01 on an Apple...

Yep ... :) looking at the docs there is an unconstrained ctor:

shared_ptr<T>::shared_ptr(shared_ptr<T1>))

with documented requirements T1* must be convertible to T*.

Because the param is unconstrained is why it fails!

In an ideal world you could try changing this ctor to something like:

template <typename T>
template <typename Derived>
shared_ptr<T>::shared_ptr(shared_ptr<Derived> const & in,
typename quanta::where_<
std::tr1::is_base_of said:
>::type* =0
){...}

(Not quite same as *convertible to* but near enough to start with, and
then your O.P. code should work OK.

Of course you probably arent living in an ideal world, however rather
than applying said SFINAE to the pointer you could do a similar SFINAE
constraint with the function and provide various overloads and get the
same effect.

regards
Andy Little
 
K

kwikius

      typename quanta::where_<
         std::tr1::is_base_of<T,Derived>,
         void*
      >::type* =0

...Oops try changing quanta::where to enable_if ;-)

regards
Andy Little
 
S

Salt_Peter

I've used Boost for this example; in fact we have our own pointer
class, for historic reasons.

#include "boost\shared_ptr.hpp"

// A heirarchy of classes
class G1 {};
class G2: public G1 {};

// A method which takes a shared pointer to the base class
void f(boost::shared_ptr<G1>) {};

// A method which takes a shared pointer to some other class
void f(boost::shared_ptr<int>) {};

void main()
{
// Call a method with a shared pointer to a derived class
f(boost::shared_ptr<G2>());

}

This fails, because the compiler is unable to decide which of the two
methods is meant. Of course, to a human, it's pretty obvious which
one is meant, but there doesn't seem to be enough information at the
time for the compiler to decide. In practice I have several hundred
functions, and 50 or so classes, to get confused among, so I don't
really want to take the obvious route [declare an
f(boost::shared_ptr<G2>) ]. Is there anything I can do to the pointer
class, or even to the class inheritance, that'll help the compiler
out?

Thx

How about templates:

#include <iostream>
#include "boost/shared_ptr.hpp"

class G1
{
public:
~G1() { std::cout << "~G1()\n"; }
};

class G2: public G1
{
public:
~G2() { std::cout << "~G2()\n"; }
};

template< typename T >
void f(boost::shared_ptr< T > bsp)
{
std::cout << "void f(boost::shared_ptr< T >&)\n";
}

template<>
void f(boost::shared_ptr<G1> bsp)
{
std::cout << "void f(boost::shared_ptr<G1>&)\n";
}

template<>
void f(boost::shared_ptr<int> bsp)
{
std::cout << "void f(boost::shared_ptr<int>&)\n";
}

int main()
{
f(boost::shared_ptr<G1>(new G2));
}

/*
void f(boost::shared_ptr<G1>&)
~G2()
~G1() // even though that dtor isn't virtual!
*/
 
N

number774

int main()
{
f(boost::shared_ptr<G1>(new G2));
}
^^^^^^^^^^^^^^^^^^^^^
That's the critical bit. (or at least, if you are in the same font as
me :) ) If the pointer passed to f *is* a shared_ptr<G1> then there's
no confusion. It's only when it's some other type that the compiler
goes hunting for a match - and finds two.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,783
Latest member
RickeyDort

Latest Threads

Top