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

ove*_*tic 4 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";

}
Run Code Online (Sandbox Code Playgroud)

在上面的代码片段中,注释掉的行不会编译.出现错误消息,它将var视为函数声明.即使A具有构造函数的参数,它仍然被视为函数声明.有没有办法写它,所以它不会被视为函数声明?在这种情况下,使用typename没有帮助.

Már*_*ldi 9

这个问题被称为最令人烦恼的解析,它准确地描述了你的情况,解析器不知道你是想要一个函数声明,还是一个对象的实例化.这是在这个意义上,给予人类,一些代码给一块呢暧昧X,但是编译器它显然做ÿ.

解决它的一种方法是使用列表初始化语法:

B var{A()}; // note the use of brackets
Run Code Online (Sandbox Code Playgroud)

这不再是模棱两可的,它会根据需要调用构造函数.您也可以A在以下两个中使用它:

B var(A{});
B var{A{}};
Run Code Online (Sandbox Code Playgroud)

现在,为什么它含糊不清?举例来说,函数参数的声明是函数的指针:

int foo(int (*bar)());
Run Code Online (Sandbox Code Playgroud)

这里,参数是函数的指针类型,它不带参数,返回类型为int.声明函数指针的另一种方法是省略声明符中的括号:

int foo(int bar());
Run Code Online (Sandbox Code Playgroud)

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

int foo(int());
Run Code Online (Sandbox Code Playgroud)

而且我们最终仍然使用相同的类型.

尽管如此,让我们检查一下你的代码并将它与上面的例子进行比较:

B var(A());
Run Code Online (Sandbox Code Playgroud)

我们有一些东西看起来像一个B初始化类型的变量声明A().到现在为止还挺好.但是等等,你说这不编译!

出现错误消息,它将var视为函数声明.

var实际上是一个函数声明,即使对你而言,它首先看起来并不像那样.此行为是由于[dcl.ambig.res]/1:

[......]决议是考虑任何可能是声明声明的构造.

这句话适用于此.回顾前面的例子:

int foo(int());
Run Code Online (Sandbox Code Playgroud)

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

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

[注意:通过在参数周围添加括号,可以明确地消除声明的歧义.通过使用复制初始化或列表初始化语法,或通过使用非函数样式转换,可以避免歧义. - 结束说明]

[例如:

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
}
Run Code Online (Sandbox Code Playgroud)

- 结束例子]