我想创建一个
std::array
的指针,而不声明指针指向的类型为const
,这样我就可以通过取消引用这些指针来更改数组指针指向的值。
所以我不想这样做:
#include <array>
int main()
{
int a = 5;
int b = 10;
std::array<const int*, 2> arr = { &a, &b }; // with const
*(arr[0]) = 20; // Because this is not possible.
}
但是这个:
#include <array>
int main()
{
int a = 5;
int b = 10;
std::array<int*, 2> arr = { &a, &b }; // without const
*(arr[0]) = 20; // Because now it is possible.
}
现在我想将这个数组传递给一个函数,这样这个函数就可以not通过取消引用这些指针来改变数组指针指向的值:
#include <array>
void test(const std::array<int*, 2>& arr)
{
*(arr[0]) = 20; // I want this to not be possible (in this example it is)
}
int main()
{
int a = 5;
int b = 10;
std::array<int*, 2> arr = { &a, &b };
test(arr);
}
我该怎么做?因为 C 数组是可能的:
void test(int const * const * const arr)
{
*(arr[0]) = 20; // this is not possible
}
int main()
{
int a = 5;
int b = 10;
int* arr[2] = {&a, &b};
test(arr);
}
我认为 C++ std 数组也应该是可能的。
非常感谢帮助。谢谢。
很遗憾,您所要求的是不可能的。
这种情况下的根本问题是 const 仅在顶层传播。
因此,使指针成为 const 只会使指针本身成为 const 而不是指向的对象。
对于任何包含指针的类都是如此,而不仅仅是
std::array
:godbolt
std::array<int*, 2> arr = { &a, &b };
auto const& arrref = arr;
static_assert(std::same_as<decltype(arrref[0]), int* const&>); // not int const * const&!
struct Foo {
int* ptr;
auto& get() const { return ptr; }
};
Foo foo{&a};
auto const& fooref = foo;
static_assert(std::same_as<decltype(fooref.get()), int* const&>); // not int const * const&!
你需要的是一个指针类型,它将其常量传播到指向的类型。
std::propagate_const
(不幸的是,作为图书馆基础知识 TS 的一部分,它仍然处于实验阶段)就是这样做的:它包装了一个类似指针的类型,以便它确实将 const 传播到指向的对象。
示例:godbolt
using std::experimental::propagate_const;
void test(std::array<propagate_const<int*>, 2> const& arr)
{
// ill-formed:
//*arr[0] = 20;
}
int main()
{
int a = 5;
int b = 10;
std::array<propagate_const<int*>, 2> arr = {&a, &b};
test(arr);
// well-formed
*arr[0] = 42;
return 0;
}
std::span
.
std::span
本质上只是一个指向数组的指针,因此您可以根据需要向元素类型添加尽可能多的常量(就像在您的 c 数组示例中,您将数组衰减为指针以添加常量)
示例:godbolt
void test(std::span<int const* const> arr)
{
// ill-formed:
//*arr[0] = 20;
}
int main()
{
int a = 5;
int b = 10;
std::array<int*, 2> arr = {&a, &b};
test(arr);
// well-formed
*arr[0] = 42;
return 0;
}
我认为没有办法实现您提到的特定要求。但是,但是,传递取消引用的整数是可以的,作者:
int modify(const int a)
{
return a;
}
int main()
{
int a = 5;
int b = 10;
std::array<int *, 2> arr = {&a, &b}; // with const
modify(*(arr[0])); // Because this is not possible.
}
我不能在函数中修改它的值。 虽然你可以简单地使用一个函数来处理这个问题,但它并不是那么开箱即用。
function A {
change array to const int array
pass const array into the function
}
或者稍微修改数组类中的运算符函数。 (矫枉过正)
有了
reinterpret_cast
,您可以实施一个快速而肮脏的解决方案:
template <typename T>
std::array<const T*, 2> const& to_const_pointers(std::array<T*, 2> const& arr) {
return reinterpret_cast<const std::array<const T*, 2>&>(arr);
}
这只是将数组解释为好像它包含指向常量元素的指针。由于
const
在这一点上是纯 C++ 的东西并且在汇编程序级别无关紧要,所以这是有效的。
#include <array>
#include <iostream>
void test(const std::array<const int*, 2>& arr)
{
// *(arr[0]) = 20; // Error as expected
std::cout << *arr[0] << ' ' << *arr[1] << '\n';
}
template <typename T>
std::array<const T*, 2> const& to_const_pointers(std::array<T*, 2> const& arr) {
return reinterpret_cast<const std::array<const T*, 2>&>(arr);
}
int main()
{
int a = 5;
int b = 10;
std::array<int*, 2> arr = { &a, &b };
test(to_const_pointers(arr));
}
5 10
std::views::as_const
和 std::span
你可能可以编写一个干净的转换。不幸的是std::views::as_const
目前没有在任何标准库中实现。