Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;nrvo/copy省略,返回语句在括号中_C++_Language Lawyer_Copy Elision_Nrvo - Fatal编程技术网

C++ C++;nrvo/copy省略,返回语句在括号中

C++ C++;nrvo/copy省略,返回语句在括号中,c++,language-lawyer,copy-elision,nrvo,C++,Language Lawyer,Copy Elision,Nrvo,我在瞎搞下面的代码,使用visual studio 2017应用程序和两个不同的在线编译器得到了不同的结果。在发布模式下,VisualStudio在这两种情况下都会省略复制/移动,而这两个在线编译器只在unparenthesized return语句的情况下执行此操作。我的问题是:谁是对的,更重要的是,基本规则是什么。(我知道可以将括号与decltype(auto)语法结合使用。但这不是当前的用例) 示例代码: #include <iostream> #include <cst

我在瞎搞下面的代码,使用visual studio 2017应用程序和两个不同的在线编译器得到了不同的结果。在发布模式下,VisualStudio在这两种情况下都会省略复制/移动,而这两个在线编译器只在unparenthesized return语句的情况下执行此操作。我的问题是:谁是对的,更重要的是,基本规则是什么。(我知道可以将括号与
decltype(auto)
语法结合使用。但这不是当前的用例)

示例代码:

#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();
}
在另外两个编译器中,输出为:

default constructor
default constructor
move constructor
这是:

这种复制/移动操作的省略称为复制省略,在以下情况下是允许的(可以组合使用以消除多个副本):

(1.1)-在具有类返回类型的函数中的return语句中,当表达式是非易失性自动对象(函数参数或处理程序([except.handle])的异常声明引入的变量除外)的名称时,该对象的类型(忽略cv限定)与函数返回类型相同,通过将自动对象直接构造到函数调用的返回对象中,可以省略复制/移动操作

所以要求是

  • 在返回语句中
  • 在函数中
  • 使用类返回类型
  • 当表达式是非易失性自动对象的名称时(函数参数或处理程序([except.handle])的异常声明引入的变量除外)
  • 具有与函数返回类型相同的类型(忽略cv限定)
  • 我认为要求1、2、3和5已经满足,但要求4没有满足<代码>(a)不是对象的名称。因此,对于给定代码,省略不适用。由于move构造函数有副作用,因此在“仿佛”规则下也不能忽略它

    因此,gcc是正确的,而visual studio(和)在这里是错误的。

    gcc是正确的

    根据:

    这种复制/移动操作的省略称为复制省略,在以下情况下是允许的(可以组合使用以消除多个副本):

    • 在具有类返回类型的函数中的
      return
      语句中,当表达式为具有相同类型(忽略cv限定)的非易失性自动对象的名称时(函数参数或处理程序([except.handle])的异常声明引入的变量除外)作为函数返回类型,可以通过将自动对象直接构造到函数调用的返回对象中来省略复制/移动操作

    return
    语句中的括号表达式不符合复制省略的条件


    事实上,在解析之前,
    return
    语句中带括号的id表达式甚至不能被视为执行移动的右值。

    这让我感到惊讶。我认为C++17需要复制省略,并且不允许兼容的实现打印
    移动构造函数
    。看起来gcc理解
    (a)
    不是
    对象的名称
    。也许把它标记为。@Someprogrammerdude有区别,但我想在日常编程中这并不重要。例如用例附带了
    decltype(auto)
    @nwp是的,我也很惊讶,但是对于括号表达式可能有一个特殊的(转换)规则。我现在认识到第一个编译器只是c++14。但是为什么它不符合标准呢?就因为名字在括号里?这只是一条简单的规则吗?我在某个地方读到,表达式的求值将导致左值,但我不知道这个。最后我觉得很奇怪
    default constructor
    default constructor
    move constructor