问题 与std :: unique_ptr的clang错误


我有一个基础对象叫 IList。然后我有 VectorList,继承 IList

然后我有这样的功能:

std::unique_ptr<IList> factory(){
    auto vlist = std::make_unique<VectorList>();
    return vlist;
}

这编译没有问题 gcc但是 clang 给出以下错误:

test_file.cc:26:9: error: no viable conversion from 'unique_ptr<VectorList, default_delete<VectorList>>' to
      'unique_ptr<IList, default_delete<IList>>'
        return vlist;

如何正确处理这种错误?


12373
2017-09-23 14:47


起源

你能提供吗? MCVE? - Chris Drew
@CoryKramer这个问题明确指出了这一点。 “我有基础对象叫 IList。然后我有 VectorList,继承 IList“。 - James Adkison
@Angew我同意,但是你 不应该明确 std::move 在回归期间 - CoryKramer
不要忘记虚拟析构函数以使其正常工作 unique_ptr。 - Rostislav
@CoryKramer这里的重点是那种类型 vlist 是 不 与返回类型相同。 vlist 是 unique_ptr<VectorList>,返回类型是 unique_ptr<IList>。因此,该标准的条款(“先行动”)不适用。 - Angew


答案:


看来(你的版本)Clang在这方面仍然遵循C ++ 11的行为。在C ++ 11中,你必须使用 std::move 在这种情况下,因为类型 vlist 与返回类型不同,因此“返回左值时,首先尝试将其作为右值”的子句不适用。

在C ++ 14中,这种对“需要相同类型”的限制被解除了,所以在C ++ 14中,你不应该需要 std::move 在退货声明中。但是如果您需要使用当前工具链编译代码,只需将其添加到那里:

return std::move(vlist);

确切的C ++ 11措辞是这样的:

12.8 / 32 当满足或将满足复制操作的省略标准时,除了源的事实   object是一个函数参数,要复制的对象由左值,重载决策指定   首先执行复制的构造函数,就好像该对象是由rvalue指定的一样。 ...

必须满足复制省略(包括“相同类型”)的标准;它们只是略微扩展到覆盖参数。

在C ++ 14(N4140)中,措辞更广泛:

12.8 / 32 当满足复制/移动操作的省略标准时,但不满足 异常声明, 和   要复制的对象由左值指定, 或者在表达中 return 声明是(可能是   括号内) ID-表达 命名具有在体内声明的自动存储持续时间的对象    参数声明子句 最里面的封闭功能或 λ-表达, 超载分辨率   首先执行选择复制的构造函数,就好像该对象是由rvalue指定的一样。

(强调我的)

如您所见,不再需要复制省略标准 return 案件。


16
2017-09-23 15:03



@Barry我添加了N4140的引用。他们没有改变副本的要求,但放宽了那些 return 声明。 - Angew
然后 这个 不应该使用编译 g++ -std=c++11, 对? - m.s.
@Barry我认为“或”的绑定比“和”弱,即我把它读作“当符合复制条件的标准时......或者当 表达 在...” - Columbo
@Columbo哦(标准遇到并且不是例外和左值)或(返回声明命名对象)?这就是为什么我们不写82个单词的句子,男孩和女孩。 - Barry
@Angew嗯,没有人为编译器销售“符合C ++ 11”的认证。它基本上意味着你可以期望编译器即使在他们的C ++ 11模式下也能实现C ++ 14的行为。 - T.C.