为什么不能将圆括号正确地视为构造函数调用?

Why can't round bracket be correctly regarded as a constructor calling?

我写了一个move来模仿std::move,尝试用一个新的struct Foo来测试一下。然而,出了点问题。

.\main.cpp: In function 'int main()':
.\main.cpp:46:7: error: conflicting declaration 'Foo x'
   46 |   Foo(x);
      |       ^
.\main.cpp:43:15: note: previous declaration as 'std::string x'
   43 |   std::string x = "123";
      |               ^

我将代码Foo(x)替换为Foo foo = Foo(x),然后一切正常。 我正在使用 MinGW32 g++ 9.2.0,使用命令 g++ main.cpp -std=c++14

进行编译

查看下面的代码了解更多详情:

#include <iostream>

template <class T>
struct Remove_Reference {
  typedef T type;
};

template <class T>
struct Remove_Reference<T&> {
  typedef T type;
};

template <class T>
struct Remove_Reference<T&&> {
  typedef T type;
};

template <typename T>
constexpr typename Remove_Reference<T>::type&& move(T&& x) noexcept {
  return static_cast<typename Remove_Reference<T>::type&&>(x);
}

struct Foo {
  Foo() {}
  Foo(std::string&& foo) : val(foo) {
    std::cout << "rvalue reference initialize" << std::endl;
  }
  Foo(const std::string& foo) : val(::move(foo)) {
    std::cout << "const lvalue reference initialize" << std::endl;
  }
  std::string val;
};

void call(std::string&& x) {
  std::cout << "rvalue reference: " << x << std::endl;
}

void call(const std::string& x) {
  std::cout << "const lvalue reference: " << x << std::endl;
}

int main() {
  std::string x = "123";

  Foo{x};
  // Foo(x);

  Foo{::move(x)};
  Foo(::move(x));

  call(x);
  call(::move(x));

  return 0;
}

这条语句:

Foo(x);

不是函数调用,也不是构造函数调用。这只是一个声明,说 xFoo 类型。括号在声明符 x 两边是可选的,所以它等价于:

Foo x;

这当然会出错,因为您已经有一个名为 xstd::string,并且您不能为同一范围内的多个实体指定相同的名称。


注意表达式:

Foo(x)

不同于上面的 语句 (带有 ;)。根据使用的上下文,此表达式可能有不同的含义。


例如,这段代码:

Foo foo = Foo(x);

完全没问题。这会从表达式 Foo(x) 复制名为 foo 的变量的初始化,表达式 Foo(x) 是根据参数 x 构造的临时 Foo。 (这里不是特别重要,但从 c++17 开始,右侧没有临时对象;对象只是就地构建)。