2010-03-02 10 views
3

В настоящее время я пытаюсь использовать Howard Hinnant's unique_ptr implementation, и я сталкиваюсь с ошибкой компиляции. Вот некоторые примеры кода:Выполняет ли реализация unique_ptr в Hinnant некорректно не преобразовывать производные на базу в этом случае?

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 
} 

Ошибки я получаю

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>]' 

Похоже, что линия нарушившей не должна потерпеть неудачу. Это ошибка в реализации, ограничение реализации из-за отсутствия языковых возможностей C++ 0x или непонимание правил unique_ptrs?

(Обратите внимание, я знаю, что это не будет работать во время выполнения, потому что я двигаюсь то же самое несколько раз, я просто пытаюсь выяснить ошибку времени компиляции.)

+1

вероятно ключевая часть описания этого «Эмуляция предназначена для захвата ** большинства ** поведения C++ 0X unique_ptr ... ". Я думаю, это означает, что не все поведение есть. –

+0

Вот статья, которая привела к такому поведению C++ 03: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf –

ответ

0

Дальнейшее исследование привело меня к this note, что привело меня к мысли, что это известное ограничение реализации:

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

Запись литба очень информативна, но я думаю, что это более прямой ответ на вопрос. Оба должны быть прочитаны заинтересованными сторонами :-) – SCFrench

1

Для подобный пример, увидеть это, который должен терпеть неудачу слишком

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

При вызове для копирования временных во втором шаге класса копирования инициализации, [...] , допускаются только стандартные последовательности преобразования и последовательности преобразования многоточия.

Именно поэтому ваш код не удался.