【发布时间】:2018-02-12 15:06:26
【问题描述】:
我正在玩弄以下代码,并使用我的 Visual Studio 2017 应用程序和两个不同的在线编译器得到了不同的结果。在发布模式下,Visual Studio 确实在这两种情况下都省略了复制/移动,而两个在线编译器只是在没有括号的 return 语句的情况下这样做。我的问题是:谁是对的,更重要的是,基本规则是什么。 (我知道您可以将括号与decltype(auto)syntax 结合使用。但这不是当前的用例)。
示例代码:
#include <iostream>
#include <cstdio>
struct Foo
{
Foo() { std::cout << "default constructor" << std::endl; }
Foo(const Foo& rhs) { std::cout << "copy constructor" << std::endl; }
Foo(Foo&& rhs) { std::cout << "move constructor" << std::endl; }
Foo& operator=(const Foo& rhs) { std::cout << "copy assignment" << std::endl; return *this; }
Foo& operator=(Foo&& rhs) { std::cout << "move assignment" << std::endl; return *this; }
};
Foo foo_normal()
{
Foo a{};
return a;
}
Foo foo_parentheses()
{
Foo a{};
return (a);
}
int main()
{
auto a = foo_normal();
auto b = foo_parentheses();
std::getchar();
}
在线编译器1: http://cpp.sh/75bux
在线编译器2: http://coliru.stacked-crooked.com/a/c266852b9e1712f3
Visual Studio 在发布模式下的输出是:
default constructor
default constructor
在其他两个编译器中,输出为:
default constructor
default constructor
move constructor
【问题讨论】:
-
这让我很吃惊。我认为 C++17 需要复制省略,并且不允许兼容的实现打印
move constructor。 -
看起来 gcc 将
(a)理解为不是object的名称。也许将其标记为language-lawyer。 -
@Someprogrammerdude 有区别,但我想这在通常的日常编程中并不重要。例如 stackoverflow.com/a/25615981/3783662 。用例带有
decltype(auto) -
@nwp 是的,我也很惊讶,但括号表达式可能有一个特殊的(转换)规则。我现在认识到第一个编译器只有 c++14。
标签: c++ language-lawyer copy-elision nrvo