Почему if constexpr не заставляет эту ошибку константного выражения ядра исчезать?
В отношении этот вопрос. Ядро константного выражения, которое используется для инициализации переменной constexpr
y
, плохо сформировано. Так много данных.
Но если я попытаюсь превратить if
в if constexpr
:
template <typename T>
void foo() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1 << x;
}
}
int main(){
foo<int>();
}
Ошибка сохраняется. С GCC 7.2 все еще дается:
error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]
Но я думал, что семантическая проверка должна быть оставлена непереработанной на отброшенной ветке.
Создание косвенности с помощью constexpr
lambda действительно помогает:
template <typename T>
void foo(){
constexpr int x = -1;
constexpr auto p = []() constexpr { return x; };
if constexpr (x >= 0){
constexpr int y = 1<<p();
}
}
Спецификатор constexpr
на y
, по-видимому, изменяет способ проверки сброшенной ветки. Это предполагаемое поведение?
@max66 был достаточно любезен, чтобы проверять другие реализации. Он сообщает, что ошибка воспроизводится как с GCC (7.2.0/Head 8.0.0), так и с Clang (5.0.0/Head 6.0.0).
Ответы
Ответ 1
В стандарте не говорится об отброшенном утверждении if constexpr
. В [stmt.if] есть по существу два утверждения:
- В прилагаемом шаблоне отбрасываемые операторы не создаются.
- Имена, на которые ссылаются от отброшенного оператора, не требуются. ODR, который должен быть определен.
Ни одно из них не относится к вашему использованию: компиляторы правильно сообщают о инициализации constexpr
. Обратите внимание, что вам нужно будет установить условие, зависящее от параметра шаблона, когда вы хотите воспользоваться преимуществами экземпляра для отказа: если значение не зависит от параметра шаблона, сбой происходит при определении шаблона. Например, этот код все еще не работает:
template <typename T>
void f() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1<<x;
}
}
Однако, если вы создаете x
в зависимости от типа T
, это нормально, даже когда f
создается с помощью int
:
template <typename T>
void f() {
constexpr T x = -1;
if constexpr (x >= 0){
constexpr int y = 1<<x;
}
}
int main() {
f<int>();
}
Ответ 2
Обратите внимание, что для оператора, отбрасываемого Constexpr If:
отброшенное утверждение не может быть плохо сформировано для каждой возможной специализации:
Чтобы исправить проблему, вы можете сделать оператор в зависимости от параметра шаблона, например
template<typename T, int X> struct dependent_value { constexpr static int V = X; };
template <typename T>
void foo() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1 << dependent_value<T, x>::V;
}
}
LIVE
Ответ 3
Я не уверен, почему вы ожидаете, что ветвь не будет проверена. Единственный раз, когда ветка if не проверена, - это когда она является частью шаблона и не создается экземпляр в соответствии с [stmt.if] p2:
Во время создания встроенного шаблона entity (раздел 17), если условие не зависит от стоимости после его создания, отброшенное подзадачу (если таковые имеются) не создается.
Ваш код, похоже, не в ситуации, когда это применимо.