constexpr if и оптимизация возвращаемого значения - PullRequest
4 голосов
/ 26 февраля 2020

У меня есть этот код:

#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 здесь. регистр в спецификации языка?

Ответы [ 2 ]

3 голосов
/ 26 февраля 2020

Это не имеет ничего общего с 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, о которых вы думаете, должны быть сделаны с временной материализацией и не применяется к NRVO, потому что x не является prvalue.

Например, этот код был недопустим до C ++ 17, и теперь он разрешен:

A test(int a)
{
    return A{a}; // legal since C++17
}
1 голос
/ 26 февраля 2020

Это NRVO , что является необязательным разрешением на копирование:

(выделение мое)

  • В выражении возврата , когда операндом является имя энергонезависимого объекта с автоматическим c сроком хранения, который не является параметром функции или параметром предложения catch и имеет тот же тип класса (игнорируя cv-qualification ) в качестве типа возврата функции. Этот вариант удаления копии известен как NRVO, «именованная оптимизация возвращаемого значения».

Это оптимизация: даже если она имеет место и конструктор копирования / move (since C++11) не вызывается, он все еще должен присутствовать и быть доступным (как если бы оптимизация вообще не происходила), в противном случае программа некорректна :


Кстати: обратите внимание, что в вашем коде оба if часть и else часть constexpr, если будет проверяться оператор .

За пределами шаблона отбрасываемый оператор полностью проверяется. если constexpr не заменяет директиву # if :

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