Почему функция constexpr ведет себя иначе для ссылки? - PullRequest
4 голосов
/ 20 октября 2019

Вдохновлен Подсчет аргументов функции во время компиляции

Рассмотрим этот код :

template <typename... Args>
constexpr int count(Args&&...)
{
    return sizeof...(Args);
}

void foo(int value)
{
    static_assert(count(value) >= 0);  // OK

    const int& ref = 7;
    static_assert(count(ref) >= 0);  // Error
}

Первый static_assert работает нормально. Второй дает ошибку:

<source>:12:19: error: static_assert expression is not an integral constant expression
    static_assert(count(ref) >= 0);
                  ^~~~~~~~~~~~~~~
<source>:12:25: note: initializer of 'ref' is not a constant expression
    static_assert(count(ref) >= 0);
                        ^
<source>:11:16: note: declared here
    const int& ref = 7;
               ^

Обе ситуации меня удивляют. Почему первый static_assert работает нормально, а value явно не известен во время компиляции? Почему второй static_assert не работает, а единственное принципиальное отличие от первого состоит в том, что он снабжен ссылкой, а не значением?

1 Ответ

3 голосов
/ 20 октября 2019

Как обычно для константных выражений, нам нужно просмотреть список в [expr.const] и посмотреть, не разрешено ли какое-либо написанное нами подвыражение. В этом случае уместным является следующий пункт:

2.11 id-выражение, которое ссылается на переменную или элемент данных ссылочного типа, если ссылка не имеет предшествующей инициализации и

  • он инициализируется константным выражением или
  • его время жизни началось в пределах оценки e;

Вот что стучит ref из воды. Он не появился с оценкой count(ref), так как он объявлен заранее и не инициализируется с помощью константного выражения. Это может быть 7, но фактический инициализатор является временным объектом, поскольку именно с этим связывается ссылка.

Что касается использования value. Это потому, что нет пули, которая запрещает value. И эталонный аргумент теперь имеет время жизни, начинающееся с оценки count(value), а не заранее. Так что это допустимая ссылка для создания в константном выражении, но ее просто нельзя использовать для чтения value.

...