С [stmt.if] / 2 (выделение мое)
Если оператор if имеет форму if constexpr, значение условия должно быть контекстуально преобразованное константное выражение типа bool; эта форма называется оператором constexpr. Если значение преобразованного условия равно false, первое подзаголовок является отклоненным оператором, в противном случае второе подзаголовок, если имеется, является отброшенным оператором. Во время создания экземпляра вмещающего шаблонного объекта ([temp.pre]), если условие не зависит от значения после его создания, исключенное подзаголовок (если есть) не создается.
Считая, что можно было бы предположить, что утверждение * stati c будет отброшено, но это не так.
Утверждение stati c запускается на первом этапе шаблона, поскольку компилятор знаю, что это всегда ложь.
С [temp.res] / 8 (выделение мое)
Достоверность шаблона может быть проверена перед любой реализацией , [ Примечание: Зная, какие имена являются именами типов, можно таким образом проверять синтаксис каждого шаблона. - примечание к концу ] Программа некорректна, диагностика не требуется c, если:
- (8.1) для шаблона не может быть сгенерирована действительная специализация или подстановка оператора constexpr if в шаблоне и шаблоне не создается , или
[...]
Да, действительно, ваш False<T>
зависит от T
. Проблема в том, что обобщенная c лямбда сама является шаблоном, а False<T>
не зависит от какого-либо параметра шаблона лямбды.
Для T
, что False<T>
ложно, c assert всегда будет ложным, независимо от того, какой аргумент шаблона отправляется лямбда-выражению.
Компилятор может видеть, что для любого экземпляра шаблона operator()
, stati c assert всегда срабатывает для текущего T. Следовательно, ошибка компилятора.
Решение для этого будет зависеть от x
:
template<typename T>
void foo() {
auto f = [](auto x) {
if constexpr(x < 0) {
static_assert(False<decltype(x)>, "AAA");
}
};
f(std::integral_constant<int, 1>{});
}
Живой пример