【问题标题】:constexpr if and the return value optimizationconstexpr if 和返回值优化
【发布时间】:2020-06-09 19:55:34
【问题描述】:

我有这个代码:

#include <string>

class A {
 public:
//    A(A const &) = delete;   // Code fails if this is uncommented.
    explicit A(int);
    explicit A(::std::string const &);

 private:
    ::std::string myname_;
    int foo_;
};

static constexpr bool which = false;

A test(::std::string const &s, int a)
{
    if constexpr (which) {
        A x{a};
        return x;
    } else {
        A y{s};
        return y;
    }
}

如果A 具有已删除的复制构造函数,则此代码将失败。但是,考虑到带有if constexpr 的函数的返回类型规则,编译器似乎应该在这里应用RVO。

除了它是语言规范中被忽视的情况之外,还有其他原因吗?

【问题讨论】:

  • 在什么编译器上这个“失败”?
  • @aschepler - 如果您取消注释删除移动构造函数,它将失败。它适用于 gcc 和 clang。
  • if constexpr 仅丢弃模板实例化中的代码。在非模板代码中,两个分支都被保留。请参阅此related question 或此one
  • @1201ProgramAlarm - 这很有趣。谢谢。

标签: c++ c++17 rvo


【解决方案1】:

这与if constexpr无关

只是这段代码不允许编译:

class A {
 public:
    A(A const &) = delete;
    explicit A(int);
};

A test(int a)
{
    A x{a};
    return x; // <-- error call to a deleted constructor `A(A const &) = delete;`
}

您正在考虑的 C++17 中的更改与 temporary materialization 有关,并且不适用于 NRVO,因为 x 不是prvalue。

例如,这段代码在 C++17 之前是非法的,现在是允许的:

A test(int a)
{
    return A{a}; // legal since C++17
}

【讨论】:

  • 啊,这确实回答了我的问题。有趣的。我对强制优化的工作方式感到困惑。
  • 我不明白为什么A x{a}; 是非法的
  • 发生的另一件事:如果A 有一个未删除的公共移动构造函数,即使表达式是左值也是合法的。但是声明一个已删除的复制构造函数意味着根本没有移动构造函数。
【解决方案2】:

这是NRVO,非强制复制省略:

(强调我的)

  • return statement 中,当操作数是具有自动存储持续时间的非易失性对象的名称时,它不是 函数参数或 catch 子句参数,哪个是 与函数返回相同的类类型(忽略cv-qualification) 类型。这种复制省略的变体被称为 NRVO,“命名返回 价值优化”。

这是一个优化:即使它发生并且没有调用 copy/move (since C++11) 构造函数,它仍然必须存在并且 可访问(好像根本没有优化),否则 程序格式错误


顺便说一句:请注意,在您的代码中,constexpr if 语句的 if 部分和 else 部分都将被检查。

在模板之外,完全检查丢弃的语句。如果 constexpr 不能替代 #if 预处理指令:

void f() {
    if constexpr(false) {
        int i = 0;
        int *p = i; // Error even though in discarded statement
    }
}

【讨论】:

  • 这是一个很好的答案,但另一个答案是对我的问题的更直接的回答。如果我第一次看到这个,我会开始争论这在 C++17 中不是真的。 :-) 我错了,但导致我意识到这一点的道路会更长。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多