【问题标题】:Is it possible to set the value of elements in a constexpr array after declaration?声明后是否可以在 constexpr 数组中设置元素的值?
【发布时间】:2017-04-04 11:08:19
【问题描述】:

是否可以在某一点声明一个 const 数组(可能是 constexpr),然后在另一个地方定义它,一次一个元素?

例如

extern constexpr int myArray[100];


myArray[0] = myConstexprFunction(0);
myArray[1] = myConstexprFunction(1);
// ...
myArray[100] = myConstexprFunction(100);

我正在尝试做的事情需要这样的东西。也许可以使用以下内容:http://b.atch.se/posts/constexpr-counter/

但是,如果这种技术在下一个 C++ 标准中是非法的(我希望不会),我想使用一种更安全的技术。

[EDIT] 放宽一些要求怎么样.. 假设我想做这样的事情:

constexpr int myConstExprFunction(int arg) { return arg + 100;}
// other code...
constexpr int a = myConstExprFunctionBegin(10);
constexpr int b = myConstExprFunction(20);
constexpr int c = myConstExprFunction(30);
constexpr int d = myConstExprFunctionEnd(40);

我想要的是 myConstExprFunctionEnd 能够使用前面函数创建的值生成最终数组。 当然,一切都在编译时进行。

[EDIT2] C++11 解决方案非常受欢迎

【问题讨论】:

  • 你试过了吗?你遇到了什么错误?
  • @RichardCritten 是的,当然我已经尝试过了,但是我得到了不同类型的错误(.. 之前已经声明过.. / 冲突声明......等等)。我可以做这样的事情的唯一方法是使用模板元编程以递归方式
  • 在英语中,句子以大写字母开头。

标签: c++ arrays c++11 constexpr


【解决方案1】:

最近的C++对constexpr的要求很宽松,可以这样写:

// requires C++17:
constexpr auto myArray = [] {
    std::array<int, 100> result {};
    for (size_t i = 0; i < 100; ++ i) {
        result[i] = i * i;
    }
    return result;
}();

请注意,我使用 std::array&lt;int, 100&gt; 而不是 int[100],因为函数无法返回 C 数组。

上述代码需要 C++17 有两个原因:

  1. constexpr lambda
  2. mutable operator[] 在 C++17 之前不是 constexpr

使用单独的 constexpr 函数可以轻松解决问题 1。问题 2 只能通过定义自己的数组包装器来解决。

// requires C++14:

template <typename T, size_t n>
struct ConstexprArray {
    T data[n];
    constexpr ConstexprArray() : data{} {}
    constexpr T& operator[](size_t i) { return data[i]; }
};

constexpr auto initialize_my_array() -> ConstexprArray<int, 100> {
    ConstexprArray<int, 100> result {};
    for (size_t i = 0; i < 100; ++ i) {
        result[i] = i * i;
    }
    return result;
}

constexpr auto myArray = initialize_my_array();

【讨论】:

  • 仍然不是我想要的,但非常有趣!你读过帖子的第二部分(编辑)吗?
  • @user3770392 第二部分如何支持C++17?
  • 我的意思是我的帖子的第二部分。顺便说一句,我只能使用 C++11。 C++14 元素,如索引等,我可以模拟它们
  • @user3770392 好的,我明白了(是的,我指的是你帖子的第二部分)。
  • ahahaa 好吧,假设我的意思只是 C++11 :)
【解决方案2】:

查看您的编辑,我只想回答,因为编译器无法将一组变量转换为数组。它只是不那样工作。 C++ 中没有任何构造可以接受一堆声明,删除它们并用另一个声明替换它。源代码预处理器或生成器可能能够允许您寻求的语法。

如果您对不需要外部工具的解决方案感兴趣,您可以创建一个返回数组的constexpr 函数:

constexpr auto makeMyArray() {
    std::array<int, 100> myArray{};

    myArray[0] = myConstExprFunction(10);
    myArray[1] = myConstExprFunction(20);
    // ...

    return myArray;
}

然后,初始化你的数组:

constexpr auto myArray = makeMyArray();

【讨论】:

  • 不在 C++11 中。但是,您可以用递归函数调用替换循环或多个语句。它需要 C++14。在 C++11 的 constexpr 函数中不能有多个语句。
  • 我想我也可以使用逗号运算符:)
  • 哦,也许吧!没想到!但我怀疑你可以用这个改变值。
  • 试试-std=c++14
  • eheheh 我知道如何使用该指令,但我现在不能使用它...
【解决方案3】:

constexpr 声明可以在编译时评估函数或变量的值。

所以你可以将它与数组一起使用的唯一方法是:

constexpr int myArray[100]{1 , 2 , 3 ,.........};

这样的语句
myArray[0] = myConstexprFunction(0);

只能在运行时进行评估。所以这是不可能的。

【讨论】:

  • 我可以使用模板元编程技术填充该数组,但这相当于创建一个 { ... }
【解决方案4】:

如果您想声明 constexpr 一个数组并使用 constexpr 函数初始化它的值...我能想到的最好的方法是将数组包装在结构/数组中并通过委托构造函数对其进行初始化。

以下是一个完整的 C++14 示例

#include <utility>
#include <iostream>

constexpr int myConstexprFunction (int i)
 { return i << 1; } // return 2*i

template <std::size_t S>
struct wrapArray
 {
   int const myWrappedArray[S];

   template <int ... Is>
   constexpr wrapArray (std::integer_sequence<int, Is...> const &)
      : myWrappedArray { myConstexprFunction(Is)... }
    { }

   constexpr wrapArray ()
      : wrapArray(std::make_integer_sequence<int, S>())
    { }
 };


int main ()
 {
   constexpr wrapArray<100>  wa100;

   for ( auto i : wa100.myWrappedArray )
      std::cout << i << ", ";

   std::cout << std::endl;
 }

如果您需要 C++11 代码,则必须实现 std::integer_sequencestd::make_integer_sequence() 的替代。这并不难。

【讨论】:

  • 是的,这与我所做的类似,但对于我的目的来说还不够。我将更详细地编辑我的问题
【解决方案5】:
猜你喜欢
  • 2019-10-06
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 2017-12-21
  • 1970-01-01
  • 2016-05-07
  • 2012-09-19
  • 1970-01-01
相关资源
最近更新 更多