constexpr if 和 return 值优化

constexpr if and the return value optimization

我有这个代码:

#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 具有已删除的复制构造函数,则此代码将失败。但是,考虑到关于 return 类型的规则,其中包含 if constexpr 的函数,似乎编译器应该在这里应用 RVO。

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

这与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 不是纯右值。

例如,此代码在 C++17 之前是非法的,现在允许使用:

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

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

(强调我的)

  • In a return statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO, "named return value optimization".

This is an optimization: even when it takes place and the copy/move (since C++11) constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed:


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

Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive:

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