在这种情况下,Hinnant 的 unique_ptr 实现是否错误地无法将派生类型转换为基类型?
我目前正在尝试使用 Howard 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 规则的误解?
(注意,我知道这在运行时不起作用,因为我多次移动同一件事;我只是想找出编译时错误。)
I'm currently trying to use Howard Hinnant's unique_ptr implementation, and am running into a compile error. Here is some 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 like the offending line should not fail. Is this a bug in the implementation, a limitation of the implementation due to the lack of C++0x language features, or a misunderstanding of the rules of unique_ptrs?
(Note, I know this won't work at run-time because I'm moving the same thing more than once; I'm just trying to figure out the compile-time error.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对于类似的示例,请参阅这也应该失败
这里的问题是如何实现移动语义:“复制构造函数”采用非常量引用,因此无法绑定到临时对象。为了仍然从临时对象中“移动”,该类有一个转换函数(以下实际上只是概念性的 - 它们的详细实现可能有所不同):
并且构造函数将采用该对象:
这是一个因相同原因而失败的示例:
现在,考虑这段代码:
复制初始化将首先转换为
A
。但随后,临时A
对象被尝试再次复制到最终对象。这需要使用operator E
的方式。但这是初始化中另一个用户定义的转换,标准禁止这样做:13.3.3.1/4
这就是您的代码失败的原因。
For a similar example, see this which should fail too
The problem here is how the move semantic is implemented: The "copy constructor" takes a non-const reference, thus not being able to bind to temporaries. To still "move" from temporaries, the class has a conversion function (following are really just conceptual - they may be differently implemented in detail):
And a constructor will take that object:
Here is an example that fails for the same reason:
Now, consider this code:
Copy initialization will first convert to
A
. But then, the temporaryA
object is tried to be copied again to the final object. This will need the way usingoperator E
. But that's another user defined conversion in the initialization, which the standard forbids:13.3.3.1/4
This is why your code fails.
进一步的研究让我看到这篇说明,让我相信这是一个已知的实现限制:
目前有 3 个测试对我来说失败了(在编译时失败,
应该编译、运行并通过)。这些都与
转换 [unique.ptr.single.ctor] 中指定的构造函数。什么时候
源和目标的类型不同,此仿真要求
转换是显式的,并且拒绝隐式编译
转换:
Further research has lead me to this note, leading me to believe that this is a known limitation of the implementation:
3 of the tests currently fail for me (fail at compile time,
supposed to compile, run and pass). These are all associated with the
converting constructor specified in [unique.ptr.single.ctor]. When
the source and target are of different type, this emulation demands
that the conversion be explicit, and refuses to compile on implicit
conversions: