2

How to initialize an array in constructor by the argument? I think type (&name)[size] syntax is pretty good and compiler maintainers can implement this easily. Is there a paragraph in the standard prohibiting such initialization?

Code:

struct Test
{
    char characters_[3];
    Test(char (&characters)[3]) : characters_(characters) {}
};

GCC version:

gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

GCC output:

FAILED: /usr/bin/c++     -Wall -Wextra -Wconversion -pedantic -Wmissing-declarations -Wmissing-include-dirs -Wfloat-equal -std=c++11 -pg   -m32 -std=gnu++11 -MMD -MT CMakeFiles/Test.dir/test.cpp.o -MF CMakeFiles/Test.dir/test.cpp.o.d -o CMakeFiles/Test.dir/test.cpp.o -c /home/user/Desktop/programms/test/Test/test.cpp
In file included from /home/user/Desktop/programms/test/Test/test.cpp:1:0:
/home/user/Desktop/programms/test/Test/test.h: In constructor ‘Test::Test(char (&)[3])’:
/home/user/Desktop/programms/test/Test/test.h:38:54: error: array used as initializer
  Test(char (&characters)[3]) : characters_(characters) {}
                                                      ^
FAILED: /usr/bin/c++     -Wall -Wextra -Wconversion -pedantic -Wmissing-declarations -Wmissing-include-dirs -Wfloat-equal -std=c++11 -pg   -m32 -std=gnu++11 -MMD -MT CMakeFiles/Test.dir/main.cpp.o -MF CMakeFiles/Test.dir/main.cpp.o.d -o CMakeFiles/Test.dir/main.cpp.o -c /home/user/Desktop/programms/test/Test/main.cpp
In file included from /home/user/Desktop/programms/test/Test/main.cpp:4:0:
/home/user/Desktop/programms/test/Test/test.h: In constructor ‘Test::Test(char (&)[3])’:
/home/user/Desktop/programms/test/Test/test.h:38:54: error: array used as initializer
  Test(char (&characters)[3]) : characters_(characters) {}
                                                      ^
Inline
  • 2,566
  • 1
  • 16
  • 32

2 Answers2

4

Perhaps the simplest solution is to use std::array instead:

std::array<char, 3> characters;
Test(std::array<char, 3> characters) : characters(characters) {}

Prior to C++11, one would have copied the argument array in the body of the constructor:

Test(char (&characters)[3]) {
    std::copy(characters, characters + sizeof characters, this->characters);
}

Or would have used a custom std::array-like wrapper.


Is there a paragraph in the standard prohibiting such initialization?

There sure is (standard draft):

[dcl.init]/17 The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression. [snip]

  • (17.1) — If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized (8.6.4).

  • (17.2) — If the destination type is a reference type, see 8.6.3.

  • (17.3) — If the destination type is an array of characters, an array of char16_t, an array of char32_t, or an array of wchar_t, and the initializer is a string literal, see 8.6.2.

  • (17.4) — If the initializer is (), the object is value-initialized.

  • (17.5) — Otherwise, if the destination type is an array, the program is ill-formed.

  • [snip]

As you can see, only a braced-init-list, string literal (for char arrays only), or an empty initializer are valid for arrays. Source type of an array is not allowed if destination is an array.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

In c++14 you could also make use of std::integer_sequence and constructor dedicated to initialize array:

#include <utility>

struct Test
{
    char characters_[3];

    Test(char (&characters)[3]) : Test(characters, std::make_index_sequence<3>{}) {}


    private:
    template <std::size_t N, std::size_t... Is>
    Test(char (&characters)[N], std::index_sequence<Is...>): characters_{characters[Is]...} {}
};

int main() {
    char abc[] = {'a', 'b', 'c'};
    Test test(abc);
}

[live demo]

To apply it in c++11 you'd need to use one of the std::integer_sequence c++11 implementations

W.F.
  • 13,888
  • 2
  • 34
  • 81