Почему функция constexpr для ссылки не constexpr?

Рассмотрим следующую функцию:

template <size_t S1, size_t S2>
auto concatenate(std::array<uint8_t, S1> &data1, std::array<uint8_t, S2> &data2) {
    std::array<uint8_t, data1.size() + data2.size()> result;

    auto iter = std::copy(data1.begin(), data1.end(), result.begin());
    std::copy(data2.begin(), data2.end(), iter);

    return result;
}

int main()
{
    std::array<uint8_t, 1> data1{ 0x00 };
    std::array<uint8_t, 1> data2{ 0xFF };

    auto result = concatenate(data1, data2);
    return 0;
}

При компиляции с использованием clang 6.0 и -std = c ++ 17 эта функция не компилируется, поскольку функция-член size в массиве не является constexpr из-за того, что она является ссылкой. Сообщение об ошибке следующее:

ошибка: аргумент шаблона, не являющийся типом, не является постоянным выражением

Когда параметры являются не ссылками, код работает должным образом.

Интересно, почему это могло быть, поскольку size () фактически возвращает параметр шаблона, вряд ли он больше может быть const. Не имеет значения, является ли параметр ссылкой.

Я знаю, что могу, конечно, использовать параметры шаблона S1 и S2, функция является лишь краткой иллюстрацией проблемы.

Есть что-нибудь в стандарте? Я был очень удивлен, когда получил ошибку компиляции.


person Martijn Otto    schedule 10.01.2019    source источник
comment
Не могли бы вы процитировать полученное вами сообщение об ошибке? И укажите, какой -std= флаг вы используете?   -  person StoryTeller - Unslander Monica    schedule 10.01.2019
comment
Компилируется, как указано в GCC 8.2. godbolt.org/z/G6_z1v. Пожалуйста, укажите версию компилятора и cpp.   -  person P.W    schedule 10.01.2019
comment
Учитывая все, пожалуйста, найдите время, чтобы сделать из этого минимально воспроизводимый пример.   -  person StoryTeller - Unslander Monica    schedule 10.01.2019
comment
Воспроизведено на godbolt.org   -  person YSC    schedule 10.01.2019
comment
Воспроизведено: MCVE   -  person YSC    schedule 10.01.2019
comment
что случилось с const_reference?   -  person Antoine Morrier    schedule 10.01.2019


Ответы (3)


Потому что вы оценили ссылку. Из [expr.const] / 4:

Выражение e является основным постоянным выражением, если только оценка e, следуя правилам абстрактной машины, не оценила бы одно из следующих выражений:

  • ...
  • an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
    • it is usable in constant expressions or
    • его время жизни началось в пределах оценки e;
  • ...

Ваш ссылочный параметр не имеет предшествующей инициализации, поэтому его нельзя использовать в постоянном выражении.

Вместо этого вы можете просто использовать S1 + S2.

person xskxzr    schedule 10.01.2019

Об этой проблеме сообщалось об ошибке для clang под названием: Clang не позволяет чтобы использовать преобразование типа constexpr в аргумент шаблона без типа.

Обсуждение в нем указывает на то, что на самом деле это не ошибка.

Выражение e является основным постоянным выражением, если оценка e, следуя правилам абстрактной машины, не оценила бы одно из следующих выражений:

  • [...]
  • an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
    • it is initialized with a constant expression or
    • его время жизни началось в пределах оценки e;
  • [...]

Вышеупомянутая цитата взята из [expr.const] /2.11 черновика n4659 с добавленным выделением.

person P.W    schedule 10.01.2019
comment
И я думаю, что это тот же TC, что и наш пользователь T.C. ^^. - person YSC; 10.01.2019
comment
@YSC: Я тоже чувствовал то же самое, но не связал его профиль, так как не был уверен. - person P.W; 10.01.2019
comment
@YSC Да, это я. - person T.C.; 10.01.2019

К сожалению, в стандарте указано, что в выражении доступа к члену класса вычисляется постфиксное выражение перед точкой или стрелкой; 63 [expr.ref] / 1. Постфиксное выражение a в a.b. Заметка действительно интересна, потому что здесь именно так:

63) Если вычисляется выражение доступа к члену класса, оценка подвыражения происходит, даже если результат не нужен для определения значения всего постфиксного выражения, например, если id-выражение обозначает статический член.

Таким образом, data оценивается, даже если в этом нет необходимости, и к нему также применяется правило фор константное выражение.

person Oliv    schedule 10.01.2019
comment
Что такого плохого в a.b оценке a (или f().b оценке f())? - person T.C.; 10.01.2019
comment
@ T.C. Когда b является статическим членом, a никогда не будет доступен! - person Oliv; 10.01.2019
comment
@ T.C. Но на самом деле я только что проверил, есть вторая ошибка дизайна в определении массива! size - нестатический член! Это безумно! В язык было внесено слишком много изменений. Вся конструкция STL устарела. - person Oliv; 10.01.2019
comment
@ T.C. 1) Зачем добавлен стандарт Постфиксное выражение перед оценкой точки или стрелки ?? Тот факт, что член является статическим или нестатическим, известен во время компиляции в каждой единице перевода, в которой он используется. 2) Есть ли в библиотечной части стандарта абзац, который дает свободу реализации выбирать, реализован ли член как статический или нестатический? Я не могу найти веских причин, чтобы заставить это сделать это. - person Oliv; 10.01.2019
comment
Что, если по какой-то причине вы хотите применить оператор & к size() в общем коде? Если это static, &size будет указателем на функцию, если не static, это будет указатель на функцию-член. Например, такой общий код не будет работать одновременно с static-расширенным std::array и std::vector. Создание size() статической функции-члена может привести к поломке некоторого существующего кода. - person Evg; 26.11.2019