在这种情况下,Hinnant 的 unique_ptr 实现是否错误地无法将派生类型转换为基类型?

发布于 2024-08-23 16:25:48 字数 2235 浏览 5 评论 0原文

我目前正在尝试使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜清冷一曲。 2024-08-30 16:25:48

对于类似的示例,请参阅这也应该失败

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

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

这就是您的代码失败的原因。

For a similar example, see this which should fail too

unique_ptr<Base> testBase = move(testDerived);

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):

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

And a constructor will take that object:

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

Here is an example that fails for the same reason:

// 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
};

Now, consider this code:

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

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

Copy initialization will first convert to A. But then, the temporary A object is tried to be copied again to the final object. This will need the way using operator E. But that's another user defined conversion in the initialization, which the standard forbids:

13.3.3.1/4

When invoked for the copying of the temporary in the second step of a class copy-initialization, [...], only standard conversion sequences and ellipsis conversion sequences are allowed.

This is why your code fails.

很酷又爱笑 2024-08-30 16:25:48

进一步的研究让我看到这篇说明,让我相信这是一个已知的实现限制:

目前有 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 .

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:

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 .
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文