【问题标题】:clang++ cannot initialize a variable of type 'int(*)[dim2]' with an rvalue of type 'int (*)[dim2]'clang++ 无法使用“int (*)[dim2]”类型的右值初始化“int(*)[dim2]”类型的变量
【发布时间】:2017-03-22 05:41:41
【问题描述】:

为什么是代码

void fcn(int *twoDArrayPtr, const int dim1, const int dim2) {
    int (*array)[dim2] = reinterpret_cast<int (*)[dim2]>(twoDArrayPtr);
}

int main() {
    return 0;
}

产生编译错误

error: cannot initialize a variable of type 'int (*)[dim2]' with
  an rvalue of type 'int (*)[dim2]'

类型相同,所以我认为可以执行分配。由于int (*)[dim2] 是一个指向大小为dim2 的数组的指针,因此可能是一个指向一组大小为dim2 的数组的指针,这些数组位于可由指针索引的连续内存中,我认为这应该可以工作。

我在 Mac OS/X 上使用 clang++,版本信息如下:

Apple LLVM 版本 6.0 (clang-600.0.56) (基于 LLVM 3.5svn)
目标:x86_64-apple-darwin14.0.0
线程模型:posix

【问题讨论】:

  • 这适用于带有 Gnu g++ 的 Linux,但不适用于 Mac OS/X...是否有一些编译器指令会有所帮助?
  • 我不知道为什么你会得到那个特定的错误,但是数组的大小必须是一个常量表达式,dim2 不是。 (GCC 除外,它在某些情况下支持可变长度数组作为非标准扩展)。

标签: c++


【解决方案1】:

dim2 不是编译时常量,C++ 中不存在 VLA(可变长度数组)。其他一些编译器(例如 gcc)具有语言扩展以允许 C++ 中的 VLA,但 clang 的行为符合标准。

您可以使用为您进行地址转换的类(或类模板)来解决该问题,例如

// This is very rudimentary, but it's a point to start.
template<typename T>
class array2d_ref {
  public:
    array2d_ref(T *p, std::size_t dim) : data_(p), dim_(dim) { }

    T *operator[](std::size_t i) { return &data_[i * dim_]; }

  private:
    T *data_;
    std::size_t dim_;
};

...

array2d_ref<int> array(twoDArrayPtr, dim2);

但是恐怕除非您在编译时知道数组的维度,否则不可能(可移植地)拥有指向数组的指针。

【讨论】:

  • 你会更新你的代码示例吗?我相信它应该在构造函数中有一个赋值。可能是data_=p?
  • 构造函数初始化列表中的data_(p) 执行赋值操作。
  • 我猜这就是我在页面中输入内容所得到的。它像现在宣传的那样工作,它会做基本的arr[foo][bar] 索引。如果您需要更复杂的指针算法,可以用更多代理类以大致相同的方式进行模拟,但是对于大多数阅读您的代码的人来说,如果您使用过普通int*。你必须决定是否值得麻烦。如果您想要两个以上的维度,那么真正的乐趣就开始了。
  • 谢谢,我几乎完全使用了这段代码,而且效果很好!
【解决方案2】:

当您使用 dim2 作为您的演员表中的数组维度时,您正在尝试使用 C99 的可变长度数组 (VLA) 功能。 (例如,gcc 通过扩展支持此功能:https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html。)

好消息,您现在不能这样做,但随着 C++14's Runtime Sized Arrays 的引入,您很快就能做到。

相关引述:

运行时大小的数组提供与 C99 的 VLA 相同的语法和性能...请记住,运行时大小的数组与 C99 的 VLA 并不完全相同。 C++14 的特性更加克制,这也是一样的。具体来说,排除了以下属性:

  • 运行时大小的多维数组
  • 函数声明语法的修改
  • sizeof(a) 是一个运行时评估的表达式,返回 a 的大小
  • typedef int a[n]; 评估 n 并将其传递给 typedef

所以你的代码很快就会合法,大约是 C++14。

我已经在 Visual Studio 2015 Beta 上试用过,遗憾的是在撰写本文时它不受支持:(

【讨论】:

  • AFAIK dynarrays 毕竟没有进入 c++14
  • @bolov 运行时大小的数组不同于 std::dynarray
  • @bolov 有趣的是我做了更多的研究,看起来 std::dynarray 和运行时大小的数组计划在 2014 年底作为 std::experimental 的一部分发布:isocpp.org/std/status 数组扩展技术规范有一个 ISO 编号,但列为“开发中”:en.cppreference.com/w/cpp/experimental
【解决方案3】:

虽然 clang 不支持变长数组,但有一个变通方法。以下使用 clang++ 4.0.0 编译:

void fcn(int *twoDArrayPtr, const int dim1, const int dim2) {
    using array_type = int (*)[dim2];
    array_type array = reinterpret_cast<array_type>(twoDArrayPtr);
}

int main() {
    return 0;
}

我不确定为什么这个别名声明会有所作为。确实看起来不一致。

【讨论】:

    猜你喜欢
    • 2019-10-05
    • 2022-01-08
    • 1970-01-01
    • 2012-01-07
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多