【问题标题】:Copy constexpr array into class将 constexpr 数组复制到类中
【发布时间】:2016-10-20 06:30:14
【问题描述】:

假设我有一堂课:

class MyClass{
  char array[12];
  public:
  MyClass(const char* arr) {
    for (int x = 0; x < 12; x++){
      array[x] = arr[x];
    }
  }
};

是否可以使MyClass 构造函数constexpr。棘手的部分是初始化新数组....

【问题讨论】:

  • 可能是一些模板诡计,再现了循环。
  • @DarthRubik - 您对 C++11 解决方案或 C++14 解决方案感兴趣?
  • @max66 C++11,因为这是一个微控制器,它无法访问 c++14 编译器(尽管 c++14 解决方案对我之后的人有用,所以你可以发布)
  • @DarthRubik - 好的;其他问题:构造函数的参数必须是const char * 或者可以是char[12] 数组?
  • @max66 如果需要,我可以是 char[12] 数组

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


【解决方案1】:

我想(我希望)下面的例子会有所帮助。

我在模板类中转换了您的MyClass,其中模板参数是数组的维度 (12);我希望不是问题。

应该使用 C++11 和 C++14

#include <iostream>

template <std::size_t ...>
struct range
 { };

template <std::size_t N, std::size_t ... Next>
struct rangeH 
 { using type = typename rangeH<N-1U, N-1U, Next ... >::type; };

template <std::size_t ... Next >
struct rangeH<0U, Next ... >
 { using type = range<Next ... >; };

template <std::size_t Dim>
class MyClass
 {
   public:
      char array[Dim];

      template <std::size_t ... rng>
         constexpr MyClass (const char arr[Dim], const range<rng...> &)
         : array{ arr[rng]... }
          { }

      constexpr MyClass (const char arr[Dim]) 
         : MyClass(arr, typename rangeH<Dim>::type())
          { }
 };


int main ()
 {
   constexpr MyClass<12> mc1("0123456789a");
   constexpr MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");

   std::cout << mc1.array << std::endl;
   std::cout << mc2.array << std::endl;

   return 0;
 }

p.s.:对不起我的英语不好

--- 编辑:添加 C++14 示例 --

如果您(当您)可以使用 C++14,则可以使用 std::index_sequencestd::make_index_sequence,避免使用 rangerangeH

例子变成

#include <utility>
#include <iostream>

template <std::size_t Dim>
class MyClass
 {
   public:
      char array[Dim];

      template <std::size_t ... rng>
         constexpr MyClass (const char arr[Dim],
                            const std::index_sequence<rng...> &)
         : array{ arr[rng]... }
          { }

      constexpr MyClass (const char arr[Dim]) 
         : MyClass(arr, std::make_index_sequence<Dim>())
          { }
 };


int main ()
 {
   MyClass<12> mc1("0123456789a");
   MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");

   std::cout << mc1.array << std::endl;
   std::cout << mc2.array << std::endl;

   return 0;
 }

-- 附录:如何避免显式维度指示--

如果你觉得在一个常量字符串中计数 char 很烦人,auto 是你的朋友;如果你以这种方式声明constexpr函数

template <std::size_t Dim>
constexpr MyClass<Dim> makeMyClass (const char (&arr)[Dim])
 { return MyClass<Dim> { arr }; }

您可以通过这种方式声明MyClass&lt;N&gt; 类型的变量(或常量)

constexpr auto mc1 = makeMyClass("0123456789a");
constexpr auto mc2 = makeMyClass("0123456789abcdefghijklmnopqrstuvwxyz");

改为

constexpr MyClass<12> mc1("0123456789a");
constexpr MyClass<37> mc2("0123456789abcdefghijklmnopqrstuvwxyz");

也适用于 C++14 和 C++11。

【讨论】:

  • @DarthRubik - 添加了一个有用的(我希望)附录
【解决方案2】:

您可以使用std::array 代替C 数组和everything just works

#include <array>

class MyClass{
  std::array<char, 12> array;
  public:
  constexpr MyClass(std::array<char, 12> arr) : array(arr){
  }
};
int main() {
    MyClass m({'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'});
}

我不知道如何用"Hello World!" 而不是那个字符列表来初始化数组。

【讨论】:

【解决方案3】:

这是一个不需要您在使用类之前指定大小的解决方案。

请注意,这是 C++14 解决方案。
无论如何,您可以轻松找到整数序列的 C++11 实现并将该解决方案调整为 C++11。

代码如下:

#include<functional>

class MyClass{
    const char arr[12];
    const std::size_t sz;

    template<std::size_t... I>
    constexpr
    MyClass(std::integer_sequence<std::size_t, I...>, const char *str)
        : arr{str[I]...}, sz{sizeof...(I)}
    { }

public:
    template<int N>
    constexpr
    MyClass(const char (&str)[N])
        : MyClass(std::make_index_sequence<N>(), str)
    { static_assert(N < 12, "!"); }

    constexpr std::size_t size() const { return sz; }
    constexpr char operator[](int n) const { return arr[n]; }
};

int main() {
    constexpr MyClass c{"foo"};
    static_assert(c.size() == 4, "!");
    static_assert(c[0] == 'f', "!");
    static_assert(c[1] == 'o', "!");
    static_assert(c[2] == 'o', "!");
    static_assert(c[3] == '\0', "!");
}

模板欺骗,如 cmets 中所述,但它有效。

【讨论】:

    【解决方案4】:

    如果您可以访问 c++14 编译器,您可以简单地使用 for 循环。但是,必须初始化内存。一个缺点是数组被写入两次,但这可能在编译时完成。一个优点是代码要简单很多。

    struct array_wrapper{
        char array[11]{};
        constexpr array_wrapper(const char (& other)[11])   {
            for (unsigned j=0;j<sizeof(other)-1;j++){
                other[j]+=text[j];
    
            }
        }
    };
    

    【讨论】:

      猜你喜欢
      • 2017-05-26
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多