2010-03-02 19 views
3

我目前正在尝试使用Howard Hinnant's unique_ptr implementation,并且遇到编译错误。下面是一些示例代码:在这种情况下,Hinnant的unique_ptr实现是否错误地将派生对象转换为基类?

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的大部分行为**“。我认为这意味着并非所有的行为都在那里。 – 2010-03-02 20:05:53

+0

以下是导致C++ 03的这种行为的论文:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf – 2010-03-02 20:40:12

回答

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

litb的书写内容非常丰富,但我认为这是对这个问题的更直接的回答。两者都应该被有兴趣的人阅读:-) – SCFrench 2010-03-17 14:24:01

1

对于一个类似的例子,请参阅本应该失败过

unique_ptr<Base> testBase = move(testDerived); 

这里的问题是,此举语义是如何实现的:在“拷贝构造函数”需要一个非const引用,因此是不能够绑定到临时工。至尚“搬家”,从临时工,班里有一个转换功能(下面是真的只是概念上的 - 他们可以在细节上有不同的实现):

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

在类复制初始化的第二步骤中调用的所述临时的复制,[...] ,只允许使用标准转换序列和省略号转换序列。

这就是为什么你的代码失败。

相关问题