Cuando queremos usar a static_asserten a if constexprdebemos hacer que la condición dependa de algún parámetro de plantilla. Curiosamente, gcc y clang no están de acuerdo cuando el código está envuelto en una lambda.
El siguiente código se compila con gcc, pero clang activa la afirmación, incluso si if constexprno puede ser cierto.
#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>();
}
Se puede arreglar fácilmente sustituyendo False<T>por False<decltype(x)>.
Entonces la pregunta es: ¿qué compilador es el correcto? Supongo que gcc es correcto porque la condición en el static_assertdepende T, pero no estoy seguro.
c++
templates
language-lawyer
c++17
static-assert
Florestan
fuente
fuente

static_assert(False<int>, "AAA");es equivalente alstatic_assert(false, "AAA");interior de la lambda.f(std::integral_constant<int, 1>{});Wandbox no activa la afirmaciónRespuestas:
De [stmt.if] / 2 (énfasis mío)
Leyendo que uno pensaría que la afirmación estática se descartaría, pero este no es el caso.
La afirmación estática se activa en la primera fase de la plantilla porque el compilador sabe que siempre es falsa.
De [temp.res] / 8 (énfasis mío)
Sí, de hecho,
False<T>depende de ustedT. El problema es que un lambda genérico es en sí mismo una plantilla yFalse<T>no depende de ningún parámetro de plantilla del lambda.Para un
TqueFalse<T>es falso, la aserción estática siempre será falsa, sin importar qué argumento de plantilla se envíe a la lambda.El compilador puede ver que para cualquier instanciación de la plantilla
operator(), la aserción estática siempre se activará para la T. actual. De ahí el error del compilador.Una solución para esto sería depender de
x:Ejemplo en vivo
fuente
La regla habitual aquí es [temp.res] / 8 :
Una vez que crea una instancia
foo<T>, lostatic_assertque tiene ya no depende. Se conviertestatic_assert(false), para todas las posibles instancias del operador de llamada de la lambda genéricaf. Eso está mal formado, no se requiere diagnóstico. Diagnósticos de argot, gcc no. Ambos son correctos.Tenga en cuenta que no importa que el
static_assertaquí se descarte.Esto mantiene al
static_assertdependiente dentro del lambda genérico, y ahora entramos en un estado donde hipotéticamente podría haber una especialización válida, por lo que ya no estamos mal formados, ndr.fuente