我有以下代码适用于 Clang 5.0 但不适用于 Clang 3.8,启用了 C++14:
class Base {};
class Derived : public Base {};
std::unique_ptr<Base> MakeDerived()
{
auto derived = std::make_unique<Derived>();
return derived;
}
int main()
{
auto base = MakeDerived();
std::cout << "Type: " << typeid(base).name() << '\n';
}
Run Code Online (Sandbox Code Playgroud)
由于复制省略,在这种情况下,返回值在技术上是移动构造的吗?如果是这样,这是否意味着unique_ptr的移动构造函数旨在支持用户类类型的隐式向上转换?很难从cppreference 文档(#6)中看出,除非我应该在该文档页面上假设模板类型与类本身的类型U明显不同T。
使这个工作显而易见的一件事是它unique_ptr不是可复制构造的,并且由于我没有通过 将其转换为右值std::move(),因此除了复制省略之外,没有其他解释为什么代码会编译。但是,因为它不适用于接受-std=c++14标志的clang 3.8,所以我想确保标准本身保证在某处(如果是,则在何处),这只是 v3.8 中的编译器错误或缺乏支持问题的铿锵。
复制省略(在 C++17 之前)总是要求被省略的构造函数实际上是可访问的,因此它不能成为您的代码工作的原因。
但是请注意,C++(自 C++11 起)有一条规则 (12.8/32) 可归结为以下规则:“返回对象时,在某些情况下,首先尝试将该对象视为右值,并且仅当失败,将其视为左值。”
在 C++11 中,这些“某些情况”是“可能复制省略”,这要求返回的对象和返回类型是相同的类型(模 cv 限定)。
在 C++14 中,这些“某些情况”被放宽为“复制省略是可能的,或者返回的对象是函数中的局部变量”。
因此,在 C++11 中,代码失败,因为std::unique_ptr<Derived>( 的类型derived)与std::unique_ptr<Base>(返回类型)不同,因此std::move必须使用。
在 C++14 中,代码成功,因为derived是函数中的局部变量,因此首先被视为右值。这使得您所指的构造函数模板适用:
std::unique_ptr<T>可以从类型为std::unique_ptr<U>if的右值构造U*为T*.
您的 Clang 3.8 似乎表现出 C++11 行为;也许它尚未(尚未/完全)在该版本中实现 C++14 的宽松方面。
(是的,确实你应该假设“模板类型”U与类的模板参数不同T。这就是它首先被引入的原因:#6 描述的构造函数是一个构造函数模板)。
| 归档时间: |
|
| 查看次数: |
592 次 |
| 最近记录: |