Very similar to this: C++ Initialize Member Array with Constructor Argument
But I don't use std::array, or rather, really rather not use it if there are other options.
I have this class (simplified):
template<typename T, int length> // Line 53
class StaticArray
{
public:
T items[length];
StaticArray() = default;
StaticArray(T newItems[length]) : items{newItems} { }
};
int main()
{
StaticArray<int, 4> a; // Works (uninitialized)
StaticArray<int, 4> b = StaticArray<int, 4>(); // Works (initialized to 0)
//StaticArray<int, 4> c = StaticArray<int, 4>({}); // Does not compile
//StaticArray<int, 4> d = StaticArray<int, 4>({1, 2, 3, 4}); // Does not compile
//StaticArray<int, 4> e = {1}; // Does not compile
return 0;
}
The lines with a and b work fine. But c does not compile:
....main.cpp:59: error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
....main.cpp:66:51: required from here
....main.cpp:59:49: error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
59 | StaticArray(T newItems[length]) : items{newItems} { }
| ^~~~~~~~
| |
| int*
Neither does d:
no matching function for call to ‘StaticArray<int, 4>::StaticArray(<brace-enclosed initializer list>)’
....main.cpp: In function ‘int main()’:
no matching function for call to ‘StaticArray<int, 4>::StaticArray(<brace-enclosed initializer list>)’
67 | StaticArray<int, 4> d = StaticArray<int, 4>({1, 2, 3, 4});
| ^
....main.cpp:59:9: note: candidate: ‘StaticArray<T, length>::StaticArray(T*) [with T = int; int length = 4]’
59 | StaticArray(T newItems[length]) : items{newItems} { }
| ^~~~~~~~~~~
....main.cpp:59:23: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘int*’
59 | StaticArray(T newItems[length]) : items{newItems} { }
| ~~^~~~~~~~~~~~~~~~
....main.cpp:58:9: note: candidate: ‘StaticArray<T, length>::StaticArray() [with T = int; int length = 4]’
58 | StaticArray() = default;
| ^~~~~~~~~~~
....main.cpp:58:9: note: candidate expects 0 arguments, 1 provided
....main.cpp:54:7: note: candidate: ‘constexpr StaticArray<int, 4>::StaticArray(const StaticArray<int, 4>&)’
54 | class StaticArray
| ^~~~~~~~~~~
....main.cpp:54:7: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const StaticArray<int, 4>&’
....main.cpp:54:7: note: candidate: ‘constexpr StaticArray<int, 4>::StaticArray(StaticArray<int, 4>&&)’
....main.cpp:54:7: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘StaticArray<int, 4>&&’
e doesn't because StaticArray is not an "aggregate type".
I don't understand the intricacies of C++ well enough to know what's going on here. I do understand that given int a[4]; int b[4]; you can't simply do a = b;. But replacing items{newItems} in the constructor with items{1, 2, 3, 4} works fine, and so does items{{1, 2, 3, 4}}!
I suspect that the whole argument type decay thing is screwing this up.
I can remove all constructors entirely and have e work, but that then allows initialization with lists that are not of the proper size, which is quite silly.
Any pointers to workarounds? I would really rather not faff about with template magic or std::array-like kajiggery. The "purer" the better.
std::array? It solves most issues with c arrays, for example you cannot copy a c-array as a wholestd::arrayis nothing more than what you need to avoid the issues that c-arrays have