c++ - 有没有办法在不使用 std::move 的情况下用构造类初始化类?

标签 c++

// Example program
#include <iostream>
#include <string>
#include <utility>

class A {
public:
    int x; 
};

class B {
public:
    B(A &&a) : m_a(std::move(a)) {}
    A m_a;
};

int main()
{
    B var(std::move(A()));
    // B var(A()); // does not compile why?

    std::cout << var.m_a.x << "\n";

}

在上面的代码片段中,被注释掉的行无法编译。错误消息似乎将 var 视为函数声明。即使 A 具有构造函数的参数,它仍然被视为函数声明。有没有一种方法可以将它写成不被视为函数声明?在这种情况下,使用 typename 没有帮助。

最佳答案

此问题称为 the most vexing parse ,这恰好描述了您的情况,解析器不知道是否需要函数声明或对象的实例化。从某种意义上说,它是模棱两可的,对于人类来说,一些给定的代码片段执行X,但对于编译器来说,它显然在执行Y

绕过它的一种方法是使用 list initialization语法:

B var{A()}; // note the use of brackets

这样就没有歧义了,你想怎么调用构造函数就怎么调用。您也可以在 A 或两者中使用它:

B var(A{});
B var{A{}};

现在,为什么它是模棱两可的?以函数参数的声明为例,该函数参数是一个指向函数的指针:

int foo(int (*bar)());

这里,参数的类型是指向函数的指针,该函数不带任何参数并且返回类型为 int。声明函数指针的另一种方法是省略声明符中的括号:

int foo(int bar());

它仍然声明了一个指向与前一个相同的函数的指针。由于我们处于声明参数 ( parameter-declaration-clause ) 的上下文中,因此被解析的语法是 type-id。 , 部分建立在 abstract-declarator 之上.因此,这允许我们删除标识符:

int foo(int());

我们仍然得到相同的类型。

综上所述,让我们检查您的代码并将其与上面的示例进行比较:

B var(A());

我们有一些看起来像 B 类型的变量声明正在用 A() 初始化。到目前为止,一切都很好。但是等等,你说这不能编译!

The error message appears that it's treating var like a function declaration.

var 实际上是一个函数声明,尽管对您来说它一开始看起来并不像那样。此行为是由于 [dcl.ambig.res]/1 :

[…] the resolution is to consider any construct that could possibly be a declaration a declaration.

这句话在这里适用。回顾前面的例子:

int foo(int());

这与您的代码一样模棱两可:foo 可能是一个声明,因此解决方案是将其解释为一个声明。您的 B var(A()) 也可能是一个声明,因此它具有相同的分辨率。

该标准在 [dcl.ambig.res]/1, example #1 上有这些案例的一些示例, 并且还提供了一些关于如何在 [dcl.ambig.res]/1, note #1 上消除歧义的提示。 :

[ Note: A declaration can be explicitly disambiguated by adding parentheses around the argument. The ambiguity can be avoided by use of copy-initialization or list-initialization syntax, or by use of a non-function-style cast. — end note  ]

[ Example:

struct S {
  S(int);
};

void foo(double a) {
 S w(int(a));                  // function declaration
 S x(int());                   // function declaration
 S y((int(a)));                // object declaration
 S y((int)a);                  // object declaration
 S z = int(a);                 // object declaration
}

— end example  ]

关于c++ - 有没有办法在不使用 std::move 的情况下用构造类初始化类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41295016/

相关文章:

c++ - 如何在 OpenGL 中绘制纹理

c++ - 我可以在编译时检查成员函数是否是运算符吗?

c++ - unordered_map 会是一个不错的选择吗?

c++ - 在 OS X 上链接期间包装符号

c++ - 宏返回值

c++ - 虚拟文件系统是该应用程序的正确概念吗

c++ - 函数开销会使程序减慢 50 倍吗?

c++ - 求 vector C++ 输入的平均值

c++ - 如何强制 GCC 假定浮点表达式为非负数?

c++ - 从另一个 CMakeLists.txt 将变量读入 cmake