Когда мы хотим использовать a static_assert
в a, if constexpr
мы должны сделать условие зависимым от некоторого параметра шаблона. Интересно, что gcc и clang не согласны, когда код обернут в лямбду.
Следующий код компилируется с помощью gcc, но clang запускает утверждение, даже если значение if constexpr
не может быть истинным.
#include <utility>
template<typename T> constexpr std::false_type False;
template<typename T>
void foo() {
auto f = [](auto x) {
constexpr int val = decltype(x)::value;
if constexpr(val < 0) {
static_assert(False<T>, "AAA");
}
};
f(std::integral_constant<int, 1>{});
}
int main() {
foo<int>();
}
Это может быть легко исправлена путем замены False<T>
на False<decltype(x)>
.
Вопрос в том, какой компилятор прав? Я бы предположил, что gcc является правильным, потому что условие в static_assert
зависит от T
, но я не уверен.
c++
templates
language-lawyer
c++17
static-assert
Флорестан
источник
источник
static_assert(False<int>, "AAA");
эквивалентноstatic_assert(false, "AAA");
внутри лямбда.f(std::integral_constant<int, 1>{});
Wandbox, не вызывает утверждения: wandbox.org/permlink/UFYAmYwtt1ptsndrОтветы:
Из [stmt.if] / 2 (выделено мое)
Читая, что можно подумать, что статическое утверждение будет удалено, но это не так.
Статическое утверждение запускается на первом этапе шаблона, потому что компилятор знает, что он всегда ложен.
Из [temp.res] / 8 (выделено мое)
Да, действительно, от тебя
False<T>
зависитT
. Проблема заключается в том, что общая лямбда сама является шаблоном иFalse<T>
не зависит от какого-либо параметра шаблона лямбды.Для
T
чтоFalse<T>
ложно, статический утверждают всегда будет ложным, независимо от того , какой шаблон аргумент передается в лямбда.Компилятор может видеть, что для любого экземпляра шаблона
operator()
статическое утверждение всегда будет срабатывать для текущего T. Отсюда и ошибка компилятора.Решение для этого будет зависеть от
x
:Живой пример
источник
Обычное правило здесь - [temp.res] / 8 :
Как только вы создадите экземпляр
foo<T>
, уstatic_assert
вас больше не будет зависимости. Это становитсяstatic_assert(false)
- для всех возможных экземпляров оператора вызова общего лямбдаf
. Это плохо сформировано, никакой диагностики не требуется. Clang ставит диагнозы, GCC нет. Оба верны.Обратите внимание , что это не имеет значения , что
static_assert
здесь будет отброшено.Это сохраняет
static_assert
зависимость в общей лямбде, и теперь мы попадаем в состояние, в котором гипотетически может быть действительная специализация, поэтому мы больше не плохо сформированы, ndr.источник