8

I wrote a class with a constexpr copy constructor. (It is a struct in example to make it simpler.) One of the fields is an array. I want copy it too.

struct Foo
{
    static constexpr int SIZE = 4;
    constexpr Foo() = default;
    constexpr Foo(const Foo &foo) :
            arr{foo.arr[0], foo.arr[1], foo.arr[2], foo.arr[3]},
            bar(foo.bar+1) {}
    int arr[SIZE] = {0, 0, 0, 0};
    int bar = 0;
};

My version works but it isn't scalable. If I change SIZE, I have to modify the constructor. In addition, code looks ugly.

Is it any better way to copy array in constructor? Constructor must be constexpr.

7
  • 7
    Doesn't the default copy constructor do the job? Commented Nov 22, 2014 at 23:33
  • Does not constexpr guarantee that the array will not be mutated? Why bother copy by value and not just a pointer? Commented Nov 22, 2014 at 23:37
  • 1
    Then you should post some code that illustrates the problem you're trying to solve. Commented Nov 22, 2014 at 23:40
  • 3
    If you need some things differently from the compiler-generated copy constructor, but do want to copy each of the array's elements by value, then my suggestion would be to not use a raw array. Wrap that in a different structure instead, and use the compiler-generated copy constructor for that different structure. (In other words, use std::array.) Commented Nov 22, 2014 at 23:40
  • 1
    The way to do it manually is make_index_sequence and delegating to a template constructor that does a pack expansion. make_index_sequence is C++14 but implementable in C++11. Commented Nov 23, 2014 at 0:03

3 Answers 3

4

In C++14 you can just use a loop to copy the array:

constexpr Foo(const Foo &foo)
    : bar(foo.bar + 1)
{
    for (int i = 0; i < SIZE; ++i)
        arr[i] = foo.arr[i];
}

That doesn't mean you should do it. I'd recommend to use std::array instead. For example, if arr is an array of some class type with non-trivial initialization, it would be default-initialized and then copied, thus wasting performance, instead of copy-initialization when using std::array and default copy constructor.

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

1 Comment

It's not a good general approach even in C++14 though: it assigns to each array element, rather than copy-constructing each array element. That doesn't matter when it's an array of int, but it does matter for other types.
3

You can use std::array. Since it is an aggregate type I believe this will work.

1 Comment

This is a good answer, but I would like to know how you can do it directly.
2

you can do something like in C++11 to just copy the array

template <int LENGTH>
constexpr bool copy_array(const char (&from)[LENGTH + 1], char (&to)[LENGTH], int index)
{
    return index < LENGTH ?  (to[index] = from[index], copy_array(from, to, ++index)) : false;
}

constexpr char src[] = "ab";
char dest[2];
copy_array(src, dest, 0);

edited: And in your context, you might be able to do something like:

#include <iostream>
#include <type_traits>
#include <array>
#include <utility>

struct Foo
{
    static constexpr int SIZE = 4;
    constexpr Foo() = default;
    constexpr Foo(const Foo &foo) :
            arr{foo.arr},
            bar(foo.bar + 1) {}
    std::array<int, SIZE> arr = {{0, 0, 0, 0}};
    int bar = 0;
};

int main()
{
    constexpr Foo foo1;
    constexpr Foo foo2(foo1);

    std::cout << foo1.bar << std::endl;
    std::cout << foo2.bar << std::endl;

    return 0;
}

2 Comments

Could you include a whole constructor definition in your example?
I tried in the context of a constexpr class constructor but it's not easy. and there's another way: template <int LENGTH> struct Foo { template <typename... Args> constexpr Foo(Args&&... args) : data{args} {} char data[LENGTH];};

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.