views:

133

answers:

3

I have the following in a for loop and the compiler says 'operator = is ambiguous'. Not sure how to solve this issue, can anyone help?

rootelement = document->getDocumentElement();
    boost::interprocess::unique_ptr<DOMNodeIterator, release_deleter> itera (document->createNodeIterator(rootelement, DOMNodeFilter::SHOW_ALL, NULL, true));
    for(boost::interprocess::unique_ptr<DOMNode, release_deleter> current (itera->nextNode()); current != 0; current = boost::interprocess::unique_ptr<DOMNode, release_deleter> (itera->nextNode()))  // Last assignment on current is ambiguous

Full error:

*

\XMLDocument.cpp(193) : error C2593: 'operator =' is ambiguous
        c:\Program Files\boost\boost_1_44\boost\interprocess\smart_ptr\unique_ptr.hpp(249): could be 'boost::interprocess::unique_ptr<T,D> &boost::interprocess::unique_ptr<T,D>::operator =(int boost::interprocess::unique_ptr<T,D>::nat::* )'
        with
        [
            T=xercesc_3_1::DOMNode,
            D=release_deleter
        ]
        unique_ptr.hpp(211): or       'boost::interprocess::unique_ptr<T,D> &boost::interprocess::unique_ptr<T,D>::operator =(boost::interprocess::rv<boost::interprocess::unique_ptr<T,D>> &)'
        with
        [
            T=xercesc_3_1::DOMNode,
            D=release_deleter
        ]
        while trying to match the argument list '(boost::interprocess::unique_ptr<T,D>, boost::interprocess::unique_ptr<T,D>)'
        with
        [
            T=xercesc_3_1::DOMNode,
            D=release_deleter
        ]
        and
        [
            T=xercesc_3_1::DOMNode,
            D=release_deleter
        ]
  \XMLDocument.cpp(193) : see reference to class template instantiation 'boost::interprocess::detail::unique_ptr_error<T>' being compiled
        with
        [
            T=boost::interprocess::unique_ptr<xercesc_3_1::DOMNode,release_deleter>
        ]
    XMLDocument.cpp(193) : see reference to class template instantiation 'boost::interprocess::detail::unique_ptr_error<T>' being compiled
        with
        [
            T=xercesc_3_1::DOMNode *
        ]
       \XMLDocument.cpp(193) : see reference to class template instantiation 'boost::interprocess::detail::unique_ptr_error<T>' being compiled
        with
        [
            T=xercesc_3_1::DOMNode *
        ]
        XMLDocument.cpp(192) : see reference to class template instantiation 'boost::int
erprocess::detail::unique_ptr_error<T>' being compiled
        with
        [
            T=xercesc_3_1::DOMNodeIterator *
        ]

*

+1  A: 

I think a std::unique_ptr can only be assigned with a call to std::move(). This is the way it explicitely loses the ownership of the underlying object.

std ::unique_ptr<T> upOldT = new T ;
std ::unique_ptr<T> pT = std ::move(upOldT) ;

As GMan has remarked, C++0x is not yet the current C++ standard, so it should be boost::interprocess::unique_ptr...

Stephane Rolland
`boost::interprocess::unique_ptr`, not `std::`. But you're correct.
GMan
@Stephane so I need to create a new unique_ptr and move the old one into it, all inside that for loop declaration?
Tony
@Tony: Normally (with `std::unique_ptr`) what you have is fine. But since your compiler doesn't support it, and Boost is faking it, you need to assist Boost in that process by moving it explicitly.
GMan
A: 

I'm not sure, and haven't tried anything, but you can try:

current = itera->nextNode()

Then it will take only one of the ambiguities.

Jan
+3  A: 

Like Stephane says, unique_ptr's maintain uniqueness unless you explicitly move them, or assign an rvalue to them. Normally, your code would be fine, but since you're faking rvalues, you'll need to move it explicitly.

I've never used boost::interprocess::unique_ptr, but it looks like you want this:

namespace bi = boost::interprocess; // do these please!
typedef bi::unique_ptr<DOMNode, release_deleter> node_ptr;
typedef bi::unique_ptr<DOMNodeIterator, release_deleter> iterator_ptr;

rootelement = document->getDocumentElement();
iterator_ptr itera(document->createNodeIterator(rootelement,
                                           DOMNodeFilter::SHOW_ALL, NULL, true));

for (node_ptr current(itera->nextNode()); current != 0;
         current = bi::move(node_ptr(itera->nextNode())))

Simpler might be:

for (node_ptr current(itera->nextNode()); current != 0;
         current.reset(itera->nextNode()))
GMan
@This is a great solution, but I think there is a problem with the current being deleted by the smart pointer on every iteration, which throws an exception inside the release() function... Perhaps I'll need a shared_ptr????
Tony