【问题标题】:(C++) My custom array cannot be initialized (compile error)(C++) 我的自定义数组无法初始化(编译错误)
【发布时间】:2018-07-20 05:41:30
【问题描述】:

我创建了一个继承 std::array 的自定义数组。 但它不能使用 std::array 的相同语句初始化。 谁能告诉我为什么这不起作用并帮助我正确修改我的代码?

这里是编译错误信息:

main.cpp: In function 'int main()':
main.cpp:32:35: error: no matching function for call to 'my_array::my_array()'
     my_array<int, 2>   b { {1, 2} }; // compile error
                                   ^
main.cpp:13:8: note: candidate: my_array::my_array()
 struct my_array : std::array<T,N>
        ^
main.cpp:13:8: note:   candidate expects 0 arguments, 1 provided
main.cpp:13:8: note: candidate: constexpr my_array::my_array(const my_array&)
main.cpp:13:8: note:   no known conversion for argument 1 from '' to 'const my_array&'
main.cpp:13:8: note: candidate: constexpr my_array::my_array(my_array&&)
main.cpp:13:8: note:   no known conversion for argument 1 from '' to 'my_array&&'

下面是我的实现代码。 提前致谢。


#include<iostream>
#include<array>

template<typename T, std::size_t N>
struct my_array : std::array<T,N>
{
    T& operator[](std::size_t n)
    {
        if(!(n < N))
            std::cout << "out of range" << std::endl;
        return (*static_cast<std::array<T,N>*>(this))[n];
    }
    const T& operator[](std::size_t n) const
    {
        if(!(n < N))
            std::cout << "out of range" << std::endl;
        return (*static_cast<const std::array<T,N>*>(this))[n];
    }
};

int main(void)
{
    std::array<int, 2> a { {1, 2} }; // no error
    my_array<int, 2>   b { {1, 2} }; // compile error
}

【问题讨论】:

  • 与您的问题无关,但 operator[] 函数没有边界检查是有原因的。如果您想要边界检查,请改用at
  • if(n > N) it is out of bound 看起来你在做相反的事情。
  • 很确定你已经违反了在 C++17 之前的编译器中使用基类聚合初始化的规则。试图找到确切的裁决。没有太多机会使用 C++17。
  • 通常,如果有人询问编译错误,必须将它们包含在问题中(通常,它们会准确说明问题所在)。

标签: c++ arrays initialization std


【解决方案1】:

我会说您的自定义类不知道带有参数 initializer_list 的构造函数,因此您必须自己实现它。

基于您的代码的快速而肮脏的解决方案,但编译和执行:

#include<iostream>
#include<array>
#include <initializer_list>

template<typename T, std::size_t N>
struct my_array : std::array<T,N>
{
  my_array(std::initializer_list<T> list)
    {
      int i=0;
      for(auto val = list.begin();val != list.end();val++) {
        std::array<T,N>::at(i++) = *val;
      }
    }


  T& operator[](std::size_t n)
    {
      if(n < N)
        std::cout << "out of range" << std::endl;
      return (*static_cast<std::array<T,N>*>(this))[n];
    }
  const T& operator[](std::size_t n) const
    {
      if(n < N)
        std::cout << "out of range" << std::endl;
      return (*static_cast<const std::array<T,N>*>(this))[n];
    }
};

int main(void)
{
  std::array<int, 2> a { {1, 2} }; // no error
  my_array<int, 2>   b { {1, 2} }; // compile error
  std::cout << b.at(0) << ", " << b.at(1) << std::endl;
}

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    std::array 使用Aggregate Initialization。不幸的是,在 C++17 之前,具有基类的类不能是聚合,这消除了 my_array

    来自 N3291 中的 [dcl.init.aggr](我有最早的 C++11 后标准草案)

    聚合是一个数组或一个类(第 9 条),没有用户提供的构造函数 (12.1),没有用于非静态数据成员 (9.2) 的大括号或均衡器,没有私有或受保护的非静态数据成员(第 11 条),无基类(第 10 条),无虚函数 (10.3)。

    C++14 稍微弱化了这些要求(N4140)

    聚合是一个数组或类(第 9 条),没有用户提供的构造函数 (12.1),没有私有或受保护的非静态数据成员(第 11 条),没有基类(第 10 条),并且没有虚函数(10.3)。

    对基类的限制仍然存在。

    当前标准修订将相关段落改写为

    聚合是一个数组或一个类(第 12 条),具有

    (1.1) — 没有用户提供的、显式的或继承的构造函数 (15.1),

    (1.2) — 没有私有或受保护的非静态数据成员(第 14 条),

    (1.3) — 没有虚函数 (13.3),并且

    (1.4) — 没有虚拟、私有或受保护的基类 (13.1)。

    允许public 基类

    AltruisticDelay 的答案通过std::Initializer_list 解决了这个限制。如果您在选择编译器或标准支持方面受到限制,这可能是您的正确答案。

    如果您可以编译成 C++17 或更新的标准,则问题中发布的代码无需修改即可编译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      相关资源
      最近更新 更多