Is the implementation of Hinnant unique_ptr incorrect to prevent the conversion of derived databases in this case?

I am currently trying to use the Howard Hinnant unique_ptr implementation and I am running a compilation error. Here is a sample code:

struct Base {};

struct Derived : public Base {};

void testfun(boost::unique_ptr<Base>);

void test()
{
    unique_ptr<Derived> testDerived; 
    unique_ptr<Base> testBase(move(testDerived)); // ok, construct base explicitly from derived 
    testfun(move(testBase));                      // ok, pass base to testfun which expects base 
    testfun(unique_ptr<Base>(move(testDerived))); // ok, explicitly converts to unique_ptr<Base>
    testfun(move(testDerived));                   // error on this line
}

The error I get is

In function 'void test()':
error: no matching function for call to 'boost::unique_ptr<Base, boost::default_delete<Base> >::unique_ptr(boost::unique_ptr<Base, boost::default_delete<Base> >)'
note: candidates are: boost::unique_ptr<T, D>::unique_ptr(boost::detail_unique_ptr::rv<boost::unique_ptr<T, D> >) [with T = Base, D = boost::default_delete<Base>]
note:                 boost::unique_ptr<T, D>::unique_ptr(boost::unique_ptr<T, D>&) [with T = Base, D = boost::default_delete<Base>]
error:   initializing argument 1 of 'void testfun(boost::unique_ptr<Base, boost::default_delete<Base> >)' from result of 'boost::unique_ptr<T, D>::unique_ptr(boost::unique_ptr<U, E>, typename boost::enable_if_c<((((! boost::is_array<U>::value) && boost::detail_unique_ptr::is_convertible<typename boost::unique_ptr<U, boost::default_delete<U> >::pointer,typename boost::detail_unique_ptr::pointer_type<T, D>::type>::value) && boost::detail_unique_ptr::is_convertible<E,D>::value) && ((! boost::is_reference<D>::value) || boost::is_same<D,E>::value)), void>::type*) [with U = Derived, E = boost::default_delete<Derived>, T = Base, D = boost::default_delete<Base>]'

It seems that the line of violation should not fail. Is this a mistake in the implementation, a limitation of the implementation due to the lack of language features of C ++ 0x, or a misunderstanding of the unique_ptrs rules?

(Note, I know that this will not work at runtime because I am moving the same thing more than once, I'm just trying to figure out a compile-time error.)

+3
source share
2 answers

, , :

3 ( , , ). , [unique.ptr.single.ctor]. , :

unique_ptr<base> b(unique_ptr<derived>()); // ok

unique_ptr<base> b = unique_ptr<derived>(); // causes 3 compile time failures under unique.ptr/unique.ptr.single/unique.ptr.single.ctor .
0

. ,

unique_ptr<Base> testBase = move(testDerived);

: " " , . - "" , ( - - ):

operator rv<T>() { return rv<T>(*this); }

:

unique_ptr(rv<T> r):ptr_(r.release()) { }

, :

// move helper. rv<> in unique_ptr
struct E { };

// simulates a unique_ptr<D>
struct D { };

// simulates the unique_ptr<B>
struct A {
  A() { }

  // accepts "derived" classes. Note that for unique_ptr, this will need that
  // the argument needs to be copied (we have a by-value parameter). Thus we 
  // automatically ensure only rvalue derived-class pointers are accepted.
  A(D) { } 

  // these will accept rvalues
  A(E) { }
  operator E() { return E(); }

private:
  A(A&); // private, error if passed lvalue
};

:

// allowed: goes: D -> A(D)
A a((D()));

// compile failure. Goes:
// D -> A(D) -> A(E)
A a = D();

A. A . operator E. , :

13.3.3.1/4

[...] .

.

+1

Source: https://habr.com/ru/post/1735085/


All Articles