【问题标题】:Initializing class member vector with size fails用大小初始化类成员向量失败
【发布时间】:2019-07-02 14:28:02
【问题描述】:

我是 C++ 新手,遇到了这个问题。这是我的代码:

class A
{
    std::vector <int> vec(10);
};

它给了我错误说expected a type specifier。我知道这种初始化向量的方式是不可接受的,应该在构造函数中完成,但我很好奇为什么会失败。我还注意到这一点:

class A
{
    std::vector <int> vec = std::vector<int>(10);
};

工作得很好。

所以我的问题是,即使我们仍在创建具有“预定义大小”(std::vector&lt;int&gt;(10))的向量,为什么第二种情况仍然有效,为什么第一种情况会失败?谢谢。

附言 我正在尝试创建大小为 10 个整数的向量,而不是创建已插入 10 的向量。

【问题讨论】:

  • 这是因为首先 sn-p 声明了一个名为 vec 的函数,该函数返回 std::vector&lt;int&gt; 并接受 参数。我想这是重复的,但也许有更好的:My attempt at value initialization is interpreted as a function declaration, and why doesn't A a(()); solve it?
  • C++11 或更高版本?使用{20} 而不是(20)。您声明了一个接受语法错误并返回 std::vector&lt;int&gt; 的函数。
  • 感谢您的回复。我试图创建一个为 6 个成员分配内存的向量,{20} 会这样做吗?
  • 这不是最令人头疼的解析错误。这是一个变量定义,但在某个地方是不允许的。
  • @mch 对于vector,因为它有 initializer_list 构造函数,所以它们不一样。 vector&lt;int&gt;(20):20 个元素,值为 0。vector&lt;int&gt;{20}:只有一个元素,值为 20。

标签: c++ visual-studio class vector


【解决方案1】:

什么?

从 C++11 开始,我们有了 non-static data member initialisers,使得这种初始化成员的方法完全有效。 但是,您必须使用={}

形式上,如果此处存在初始化程序,则 it must bebrace-or-equal-initializer 语法产生。

由于您在这里使用了不计为初始化的语法,因此编译器会尝试从 vec 中创建一个函数声明,这会因为 20 不是类型而中断。


为什么?

原始功能提案 (N2756) 中名为“问题 1”的章节解释说,此处不允许使用 (),以避免与成员函数声明相关的一些混淆。

作者确实在其中指出,委员会可以让它存在,并让它像其他声明一样工作——也就是说,如果可以,它就是一个函数,否则就是一个对象*。但是作者决定换个方向,只是禁止语法以避免在这种特殊情况下出现问题。

不幸的是,这使得“(expression-list)”形式的初始化器在解析声明时变得模棱两可 [..]

一种可能的解决方案是依靠现有规则,即如果声明可以是对象或函数,那么它就是函数 [..]

类似的解决方案是应用另一个现有规则,目前仅在模板中使用,如果T 可以是类型或其他东西,那么它就是其他东西;如果我们真的是指类型 [..]

,我们可以使用“typename

这两种解决方案都引入了许多用户可能会误解的微妙之处(comp.lang.c++ 上关于为什么“int i();”在块范围内的许多问题证明了这一点。 t 声明一个默认初始化的int)。

本文提出的解决方案是只允许“= initializer-clause”和“{ initializer-list }”形式的初始化器。 这解决了大多数情况下的歧义问题。

这就是生活。


那么?

我正在尝试创建大小为 10 个整数的向量,而不是创建一个已插入 10 个整数的向量。

这是很重要的一点。小心,因为用{} won't do that 初始化向量。不幸的是,“统一”初始化merely added more meanings。解决歧义问题就这么多……

因此,您应该使用= 语法,或者只在构造函数中执行此操作(我最喜欢)。


* 这是most vexing parse 有时会咬你的地方,尽管并非每次出现的意外函数声明都是最令人头疼的解析示例。

【讨论】:

  • 谢谢你的详细解释:)
  • @user3503143 不客气!我不知道这个,所以也学到了一些东西。
【解决方案2】:

写得不好。您也可以使用以下示例。在这里,我将向量留空,但 reserve() 有 20 个指针的空间,因此您可以插入而无需重新分配。一个更简单更好的解决方案(使用构造函数)是:

A.cpp

#include "A.hpp"

A::A()
{
   this->vec.reserve(20);
   std::cout << "Setting size" << std::endl;
}
A::~A()
{
}

A.hpp

#ifndef A_HPP
#define A_HPP_

#include <iostream>
#include <vector>

class A {
public:
        A();
        ~A();
        std::vector<int> vec;
};

#endif /* !A_HPP_ */

main.cpp

#include "A.hpp"

int main()
{
   A a;
}

输出:

Setting size

你的矢量大小就完成了。

【讨论】:

  • 不是放错地方了,是允许的,只是写错了。
【解决方案3】:

您不能使用 type name(value); 语法声明和初始化成员变量,但可以使用 type name{value};type name = value;

这是来自标准的语法:

[class.mem]/1

member-declaration:
  attribute-specifier-seq(opt) decl-specifier-seq(opt) member-declarator-list(opt);
  [...]
member-declarator-list:
  member-declarator
  member-declarator-list , member-declarator
member-declarator:
  [...]
  declarator brace-or-equal-initializer(opt)
  [...]

[dcl.init]/1

brace-or-equal-initializer:
  = initializer-clause
  braced-init-list
braced-init-list:
  { initializer-list , (opt) }
  { designated-initializer-list , (opt) }
  { }

所以如下:

class C
{
    int a = 0;
    int b{0};
}

有效。

C::a 的定义是一个 member-declaration,其中 member-declarator-list 由一个用 brace-or- 初始化的单个成员组成= initializer-clause 形式的等式初始化器

同样,C::b 使用 braced-init-list 形式。

另一方面,您会发现 int c(0); 没有语法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-25
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多