什么时候指向数组的指针可以转换为不同类型的指向数组的指针?

时间:2017-03-24 06:18:29

标签: c++ c++17

我正在查看std::unique_ptr std::unique_ptr<T[]>并注意到C ++ 17似乎已经做了一些有趣的改动。特别是,std::unique_ptr::pointer的特化现在接受模板参数,它之前只接受reset个参数。例如,以下是std::unique_ptr<T[]>的一个template <typename U> void reset(U p); 成员函数的声明:

reset

该网站声明:

  

与主模板的U成员的行为相同,只是它只参与重载解析   pointerpointer的类型相同,或者   element_type*U的类型相同,而V*是指针类型V(*)[],因此element_type(*)[]可转换为delete[]

我假设这是为了安全 - 你不想对指向指向其基类型指针的派生类型数组的指针执行#include <type_traits> struct foo {}; struct bar : public foo {}; static_assert(!std::is_convertible_v<bar(*)[], foo(*)[]>); (在C +之前) +17这被标记为已删除)。正如所料,这段代码编译得很好:

static_assert

然而,有趣的是,以下编译,两个#include <type_traits> struct foo {}; struct bar : public foo {}; static_assert(std::is_convertible_v<bar*(*)[], foo*(*)[]>); static_assert(std::is_convertible_v<std::unique_ptr<bar>(*)[], std::unique_ptr<foo>(*)[]>); 都失败了:

$scope.onSelect = function(item) {
  // you existing code...
  if($scope.newData.category === "Add new category") {
    $scope.newData.category = ''; // set to empty string so the input box is empty
    $scope.showAddCategory = true;
  }
}

为什么?在什么情况下会使用这种重载?

2 个答案:

答案 0 :(得分:5)

这基本上是一种说法“如果可以安全地传递一个较少的常量指针”,例如,int* p = /*...*/; unique_ptr<const int []> up; up.reset(p);

对于不同类型UVU(*)[](隐式)可转换为V(*)[]的唯一情况是qualification conversion,即您要在类型中的正确位置添加const / volatile。确切的规则很复杂(因为它们处理任意嵌套的指针/指向成员/数组的指针;如果你想知道的话,点击链接),但它们基本上只允许在安全时进行转换; unique_ptr的规范然后利用这个事实,这样它就不必重新定义“安全”,代价是使意图变得更加神秘。

答案 1 :(得分:0)

struct foo {};
struct bar : public foo {};

在这个简单的案例中,foo*的值表示很可能与bar*的值表示完全相同,因此可以可以在它们的数组之间进行转换。但是,只要bar变得更复杂,它就不再成立。考虑一下:

struct foo {};
struct qux {};
struct bar : qux, foo {};

现在,bar*可隐式转换为foo*,但该转化不会保留其准确值:它需要从quxfoo的偏移。< / p>

同样,只要虚拟,多个访问控制级别等进入图片,基类子对象的地址就会变得与最派生对象的地址不同。这样的指针甚至可以具有不同的大小(1)

这就是为什么只有一组有限的案例,derived*可以用作base*而没有改变价值的转化。我的猜测是,对有限的情况进行补贴会使标准变得复杂,效果不大,因此不允许在这些指针数组之间进行转换。

(1)这有点模糊,但如果C ++编译器受到设计不佳的C ABI的限制,可能会发生这种情况。 This answer讨论了这种情况。