Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy constexpr array into class

Suppose I have a class:

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

Is it possible to make the MyClass constructor constexpr. The tricky part is initializing the new array....

like image 700
DarthRubik Avatar asked Jun 18 '16 14:06

DarthRubik


2 Answers

I suppose (I hope) the following example could help.

I transformed your MyClass in a templated class where the template parameter is the dimension of the array (12); I hope isn't a problem.

Should work with C++11 and 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.: sorry for my bad English

--- edit: added C++14 example --

If you (when you) can use C++14, you can use std::index_sequence and std::make_index_sequence, avoiding range and rangeH.

The example become

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

-- addendum: how to avoid explicit dimension indication --

If you find annoying count the char in a constant string, auto is your friend; if you declare a constexpr function in this way

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

you can declare your variables (or constants) of type MyClass<N> in this way

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

instead

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

Works with C++14 and C++11 too.

like image 195
max66 Avatar answered Sep 25 '22 08:09

max66


You can use an std::array instead of a C-array and 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', '!'});
}

I don't know how to initialize the array with "Hello World!" instead of that list of characters.

like image 40
nwp Avatar answered Sep 25 '22 08:09

nwp