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

Dun*_*can 2 c++ c++17

我正在查看cppreference文档,std::unique_ptr并注意到C++ 17似乎已经做了一些有趣的更改.特别是,std::unique_ptr<T[]>现在的特化接受模板参数,它之前只接受std::unique_ptr::pointer参数.例如,以下是其中一个reset成员函数的声明std::unique_ptr<T[]>:

template <typename U> void reset(U p);
Run Code Online (Sandbox Code Playgroud)

该网站声明:

行为一样的reset主模板的成员,但它只会参与重载分辨率如果任 U是相同的类型pointer,或者 pointer是相同的类型element_type*U是指针类型V*,使得V(*)[]可转换为element_type(*)[].

我假设这是为了安全 - 你不想delete[]在指向指向其基类型指针的派生类型数组的指针上执行(在C++ 17之前,这被标记为已删除) .正如所料,此代码编译良好:

#include <type_traits>

struct foo {};
struct bar : public foo {};
static_assert(!std::is_convertible_v<bar(*)[], foo(*)[]>);
Run Code Online (Sandbox Code Playgroud)

然而,有趣的是,以下内容无法编译,两者都失败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>(*)[]>);
Run Code Online (Sandbox Code Playgroud)

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

T.C*_*.C. 5

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

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