Почему std :: swap разрешен в этой функции constexpr? - PullRequest
6 голосов
/ 11 марта 2019

Я написал функцию, вычисляющую gcd двух чисел, которая использует std::swap в случае, когда второй параметр больше первого.

Некоторое время спустя я понял, что std::swap - это , а не constexpr, но моя функция по-прежнему компилируется и успешно выполняется.
Я пытался с MinGW-w64 8.1.0 и Visual C ++ 2017, и он работал для обоих.

Моя первая мысль была о том, что constexpr функции разрешено выполнять во время выполнения, поэтому я попробовал std::integral_constant<int,gcd(32,12)>, и это сработало.

Однако я не могу использовать ни одну из своих собственных функций не-constexpr (что я и ожидаю).

Вот мой тестовый код:

#include <utility>

inline void foo() noexcept {
}

template<typename T>
constexpr T gcd(T a, T b) {
    // foo();            // only works with non-constexpr j
    if(a<b) {
        std::swap(a, b); // works for both constexpr i and non-constexpr j
    }
    if(b==0) {
        return a;
    } else {
        return gcd(b, a%b);
    }
}

int main()
{
    constexpr int i = std::integral_constant<int, gcd(32, 12)>::value;
    int j = gcd(32,12);
}

Итак, мой вопрос: почему я могу использовать std::swap в своей функции?

1 Ответ

8 голосов
/ 11 марта 2019

Вот соответствующая цитата из cppreference :

Функция constexpr должна удовлетворять следующим требованиям:

  • ...
  • существует, по крайней мере, один набор значений аргументов, так что вызов функции может быть оцененным подвыражением основного константного выражения

СуществуетПуть, который не проходит через std::swap(), где a>=b.Фактически, для gcd(32, 12) выполнение никогда не проходит std::swap().

РЕДАКТИРОВАТЬ : Я посмотрел на C ++ 14 черновик .Раздел 7.1.5 Спецификатор constexpr .Параграф 5 гласит:

Для не шаблонной, не дефолтной функции constexpr [...], если не существует значений аргумента, так что вызов функции или конструктора может быть оцененным подвыражениемосновное константное выражение (5.20), или, для конструктора, инициализатор константы для некоторого объекта (3.6.2), программа плохо сформирована;

и пример, который они дают:

constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...