如何将 std::array 作为 const 传递?

问题描述 投票:0回答:3

我想创建一个

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 数组也应该是可能的。

非常感谢帮助。谢谢。

c++ arrays pointers parameter-passing std
3个回答
1
投票

很遗憾,您所要求的是不可能的。

这种情况下的根本问题是 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;
}

另一个适用于 C++20 的选项是使用

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;
}

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
}

或者稍微修改数组类中的运算符函数。 (矫枉过正)


0
投票

有了

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

使用 C++23

std::views::as_const
std::span
你可能可以编写一个干净的转换。不幸的是
std::views::as_const
目前没有在任何标准库中实现。

© www.soinside.com 2019 - 2024. All rights reserved.