【问题标题】:How do you copy a constexpr array to another constexpr array with std::copy?如何使用 std::copy 将 constexpr 数组复制到另一个 constexpr 数组?
【发布时间】:2017-05-26 19:00:09
【问题描述】:

在下面的代码中,我创建了一个长度为 6 的数组,并在前 3 个元素中使用 1、2 和 3 对其进行初始化。然后我将前 3 个元素复制到后 3 个元素。然后我按顺序打印所有元素。

std::array<int, 6> bar = {1, 2, 3};

int main(){
    // Copy the first 3 elements to the last 3 elements
    std::copy(bar.begin(), bar.end() - 3, bar.end() - 3);

    // Print all the elements of bar
    for(auto& i: bar) std::cout << i << std::endl;
}

它工作正常,但是当我尝试使数组 constexpr 它不再编译时:

constexpr std::array<int, 6> bar = {1, 2, 3};

int main(){
    // Copy the first 3 elements to the last 3 elements
    std::copy(bar.begin(), bar.end() - 3, bar.end() - 3); // Won't compile!

    // Print all the elements of bar
    for(auto& i: bar) std::cout << i << std::endl;
}

使用g++ -std=c++14 main.cpp -o main 编译我收到以下错误消息:

/usr/include/c++/5/bits/stl_algobase.h: In instantiation of ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = const int*; _OI = const int*]’:
/usr/include/c++/5/bits/stl_algobase.h:438:45:   required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = const int*; _OI = const int*]’
/usr/include/c++/5/bits/stl_algobase.h:471:8:   required from ‘_OI std::copy(_II, _II, _OI) [with _II = const int*; _OI = const int*]’
main.cpp:115:53:   required from here
/usr/include/c++/5/bits/stl_algobase.h:402:44: error: no matching function for call to ‘std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m(const int*&, const int*&, const int*&)’
                        _Category>::__copy_m(__first, __last, __result);
                                            ^
/usr/include/c++/5/bits/stl_algobase.h:373:9: note: candidate: template<class _Tp> static _Tp* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = _Tp; bool _IsMove = false]
         __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result)
         ^
/usr/include/c++/5/bits/stl_algobase.h:373:9: note:   template argument deduction/substitution failed:
/usr/include/c++/5/bits/stl_algobase.h:402:44: note:   deduced conflicting types for parameter ‘_Tp’ (‘int’ and ‘const int’)
                        _Category>::__copy_m(__first, __last, __result);

我完全不明白这个错误信息。 std::copy 不是 constexpr?如果不是,应该是,对吧?如果std::copyconstexpr,我的代码会起作用吗?

【问题讨论】:

  • 如果数组是const,则不能更改。
  • 我对新的 C++ 特性没有太多经验,但是如果你想在之后修改它,声明一个数组 constexpr 是没有意义的。要么,数组是常量,要么不是。
  • @latedeveloper 如何在编译时制作不是 'const' 的东西?
  • @WillyGoat - 正是……你想在编译时做什么?复制数组中的值列表?
  • @Willy 我不明白你在问什么。

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


【解决方案1】:

你应该创建一个 constexpr 函数。 constexpr 隐含 const,但不在 constexpr 函数的范围内。

constexpr auto get_bar() {
    std::array<int, 6> bar = {1, 2, 3, 0, 0, 0};

    copy(bar.begin(), bar.end() - 3, bar.end() - 3);

    return bar;
}

但是,您需要编写自己的 copy 版本,因为它在标准库中没有标记为 constexpr

更改编译时数组的值没有意义,这与要求编译器在运行时更改变量的类型是一回事。编译器在运行时甚至不存在。然而,一个 constexpr 函数是由编译器执行的,所以要求它改变值仍然是有意义的。这就是为什么上面的代码有意义。

请注意,在 C++17 之前,大多数 std::array 访问器不是 constexpr

【讨论】:

  • 另请注意,std::array&lt;T, n&gt;::begin()std::array&lt;T, n&gt;::end() 和所有其他访问器自 C++17 以来仅是 constexpr
  • @yurikilochek 确实,我会将其添加到答案中。
  • 谢谢。我真的很感谢你的第二句话。我对constexpr 的常量感到困惑。对我来说,如果您希望在编译时对其进行评估,那么必须为 const 仍然没有意义。如果您需要预先计算一个在运行时会改变的巨大数组怎么办?
  • @WillyGoat 我在答案中添加了一段。希望对您有所帮助。
【解决方案2】:

constexpr 暗示const

您的std::copy 尝试修改const 变量。

--- 编辑---

OP问

我正在实现一些使用非常大的预先计算值数组的东西,这些值会环绕一次。如果不打印出值并将它们复制粘贴到我的代码中,我就无法做到这一点?

下面的内容呢?

#include <array>
#include <iostream>

template <int ... I>
struct foo
 { std::array<int, 2U*sizeof...(I)> bar { { I..., I... } }; };

int main()
 {
   foo<2, 3, 5, 7, 11, 13> v;

   for ( auto const & i : v.bar )
      std::cout << i << ", ";

   // the for print 2, 3, 5, 7, 11, 13, 2, 3, 5, 7, 11, 13,

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

【讨论】:

  • 如何解决这个问题?我不介意数组在运行时为 const,但我希望能够在编译时以编程方式对其进行编辑。
  • 不要让它成为常量。如果你想改变它,为什么要把它设为 const?
  • @WillyGoat - 一个const (constexpr) 变量只能被初始化;您必须在初始化中插入所有值;如果您想在编译时做某事,则必须是 constexpr 或 templape 参数。
  • 我很欣赏编辑。这是一些疯狂的 C++,但我最喜欢 Guillaume 的解决方案。谢谢! :)
  • @WillyGoat - 你很高兴 :)
猜你喜欢
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
  • 2019-09-24
  • 1970-01-01
  • 2013-10-24
相关资源
最近更新 更多