Что касается этот вопрос. Ядро константное выражение, которое используется для инициализации 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
Однако лямбда помогает:
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).
Стандарт мало что говорит о отклоненное заявление из if constexpr
, По сути, в [stmt.if] есть два утверждения об этом:
Ничто из этого не относится к вашему использованию: компиляторы вправе жаловаться на 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>();
}
Обратите внимание, что для заявления, отбрасываемого 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;
}
}
Я не уверен, почему вы ожидаете, что ветка не будет проверена. Единственный раз, когда ветвь if не проверяется, это когда она является частью шаблона, а не инстанцирован, согласно [stmt.if] p2:
Во время создания шаблона
Сущность (пункт 17), если условие не зависит от значения после его создания, отбрасываемое подзаголовок
(если есть) не был создан.
Ваш код, кажется, не в такой ситуации.