使用构造函数参数初始化成员数组(使用普通旧数组)

Initialize member array with constructor argument (with plain old arrays)

与此非常相似:
但我不使用 std::array,或者更确切地说,如果有其他选择,我宁愿不使用它。

我有这个class(简体):

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

带有 ab 的行工作正常。但是 c 不编译:

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

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 不是因为 StaticArray 不是“聚合类型”。

我不太了解 C++ 的复杂性,不知道这里发生了什么。我明白给定 int a[4]; int b[4]; 你不能简单地做 a = b;。但是用 items{1, 2, 3, 4} 替换构造函数中的 items{newItems} 效果很好, items{{1, 2, 3, 4}}!
我怀疑是整个参数类型衰减问题搞砸了。
我可以完全删除所有构造函数并让 e 工作,但是这样就允许使用大小不合适的列表进行初始化,这很愚蠢。

任何解决方法的指示?我真的不想用模板魔术或 std::array 之类的 kajiggery。越“纯”越好

这个构造函数:

template<typename... TNewItems>
StaticArray(TNewItems... newItems)
: items{newItems...}
{
    static_assert(sizeof...(newItems) == length, "Number of supplied items must match the length of the array.");
}

这样使用:

  StaticArray<int, 4> a;                                     // Works (uninitialized for int, calls the default constructor for complex types)
  StaticArray<int, 4> b = StaticArray<int, 4>();             // Works (0, 0, 0, 0)
  StaticArray<int, 4> c = StaticArray<int, 4>({});           // Weirdly works (0, 0, 0, 0; does not call the custom constructor)
  StaticArray<int, 4> d = StaticArray<int, 4>({1, 2, 3, 4}); // Works (1, 2, 3, 4)
  StaticArray<int, 4> e =                     {1, 2, 3, 4};  // Works (1, 2, 3, 4)
//StaticArray<int, 4> f = StaticArray<int, 4>({1, 2});       // Fails to compile
//StaticArray<int, 4> g =                     {1, 2};        // Fails to compile

模板魔法相当小。初始化列表中 wong 类型的错误消息(就 C++ 通常捕获错误类型而言)非常清晰,即使是模板化的 类.
static_assert 允许检查不正确数量的项目。不匹配时的错误消息非常清晰。
导致所有内容都被初始化为 0 的空初始化列表有点奇怪,但还算不错。