5

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....

5
  • May be some template trickery, reproducing the loop. Commented Jun 18, 2016 at 14:40
  • @DarthRubik - you're interested in a C++11 solution or in a C++14 solution? Commented Jun 18, 2016 at 15:04
  • @max66 C++11, because this is for a micro controller, which does not have access to a c++14 compiler (although a c++14 solution would be useful to people after me, so you could post that) Commented Jun 18, 2016 at 15:05
  • @DarthRubik - ok; other question: the argument of the constructor must be a const char * or can be a char[12] array? Commented Jun 18, 2016 at 15:11
  • @max66 I could be a char[12] array if it needed to be Commented Jun 18, 2016 at 15:12

4 Answers 4

9

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.

Sign up to request clarification or add additional context in comments.

1 Comment

@DarthRubik - added a usefull (I hope) addendum
1

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.

1 Comment

I think you could use std::experimental::to_array to initialize it? If you don't have that, you can borrow the example implementation: en.cppreference.com/w/cpp/experimental/to_array
1

Here is a solution that does not require you to specify the size before to use the class.

Note that this is a C++14 solution.
Anyway, you can easily find a C++11 implementation of the integer sequence stuff and adapt the solution to C++11.

Here is the code:

#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', "!");
}

Template trickery, as mentioned in the comments, but it works.

Comments

0

In case you have access to a c++14 compiler you can simply use a for-loop. However, the memory has to be initialized. A disadvantage is that the array is written twice, but that might be done while compiling. An advantage is that the code is a lot simpler.

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];

        }
    }
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.