【问题标题】:Why can't round bracket be correctly regarded as a constructor calling? [duplicate]为什么不能正确地将圆括号视为构造函数调用? [复制]
【发布时间】:2020-09-14 14:07:34
【问题描述】:

我写了一个move来模仿std::move,并尝试使用一个新的结构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}; 应该做什么?创建一个匿名临时?
  • @DanielLangr 是的
  • 对不起,在我之前的评论中应该是Foo(x);。这里也是标准的相关部分:eel.is/c++draft/stmt.ambig。不管怎样,你可以改写Foo(x).val;
  • 你可能想查找“最令人头疼的解析”。
  • @n.'pronouns'm。查找是一个好主意,但是Foo(x); 没有令人烦恼的解析。它不能是函数声明。

标签: c++ constructor definition


【解决方案1】:

此声明:

Foo(x);

不是函数调用,也不是构造函数调用。这只是一个声明,表示x 的类型为Foo。声明符 x 周围的括号是可选的,因此它相当于:

Foo x;

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


注意表达式

Foo(x)

不同于上面的语句(带有;)。这个表达式可能意味着不同的东西,具体取决于它所使用的上下文。


例如这段代码:

Foo foo = Foo(x);

完全没问题。这确实从表达式 Foo(x) 复制了名为 foo 的变量的初始化,该表达式是从参数 x 构造的临时 Foo。 (这里不是特别重要,但从 c++17 开始,右侧没有临时对象;对象只是在适当的位置构造)。

【讨论】:

  • 为什么?这是歧义的一部分吗?
  • 我不确定你的意思。这里没有歧义,只是Foo x;Foo (x);Foo ((x));在c++中都是等价的。
  • 不能将Foo foo = Foo(x)视为调用Foo(x),然后分配给Foo foo
  • @cigien 其实貌似有:eel.is/c++draft/stmt.ambig.
  • @DanielLangr 哦,我明白你现在的意思了。编辑答案更清楚。感谢您指出这一点。
猜你喜欢
  • 2021-02-18
  • 2014-01-14
  • 1970-01-01
  • 2019-09-14
  • 1970-01-01
  • 1970-01-01
  • 2021-05-14
  • 2014-01-24
相关资源
最近更新 更多