Wenn wir a static_assert
in a verwenden möchten, if constexpr
müssen wir die Bedingung von einem Vorlagenparameter abhängig machen. Interessanterweise stimmen gcc und clang nicht überein, wenn der Code in ein Lambda eingewickelt ist.
Der folgende Code wird mit gcc kompiliert, aber clang löst die Bestätigung aus, auch wenn das if constexpr
nicht wahr sein kann.
#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>();
}
Es kann leicht durch Ersetzen False<T>
durch behoben werden False<decltype(x)>
.
Die Frage ist also: Welcher Compiler ist richtig? Ich würde annehmen, dass gcc korrekt ist, da die Bedingung in der static_assert
abhängig ist T
, aber ich bin nicht sicher.
c++
templates
language-lawyer
c++17
static-assert
florestan
quelle
quelle
static_assert(False<int>, "AAA");
entspricht demstatic_assert(false, "AAA");
Inneren des Lambda.f(std::integral_constant<int, 1>{});
Wandbox lautet, wird die Bestätigung nicht ausgelöst: wandbox.org/permlink/UFYAmYwtt1ptsndrAntworten:
Aus [stmt.if] / 2 (Schwerpunkt Mine)
Wenn man liest, dass man denken würde, die statische Behauptung würde fallengelassen, aber das ist nicht der Fall.
Die statische Zusicherung wird in der ersten Phase der Vorlage ausgelöst, da der Compiler weiß, dass sie immer falsch ist.
Aus [temp.res] / 8 (Schwerpunkt Mine)
Ja, das
False<T>
hängt davon abT
. Das Problem ist, dass ein generisches Lambda selbst eine Vorlage ist undFalse<T>
nicht von einem Vorlagenparameter des Lambda abhängig ist.Für a
T
,False<T>
das falsch ist, ist die statische Zusicherung immer falsch, unabhängig davon, welches Vorlagenargument an das Lambda gesendet wird.Der Compiler kann sehen, dass bei jeder Instanziierung der Vorlage
operator()
die statische Zusicherung immer für das aktuelle T ausgelöst wird. Daher der Compilerfehler.Eine Lösung hierfür wäre
x
:Live Beispiel
quelle
Die übliche Regel hier ist [temp.res] / 8 :
Sobald Sie instanziieren
foo<T>
, ist das, wasstatic_assert
Sie haben, nicht mehr abhängig. Es wirdstatic_assert(false)
- für alle möglichen Instanziierungen des Anrufbetreibers des generischen Lambdaf
. Das ist schlecht geformt, keine Diagnose erforderlich. Clang diagnostiziert, gcc nicht. Beide sind richtig.Beachten Sie, dass es nicht , dass das keine Rolle
static_assert
hier wird verworfen.Dies hält die
static_assert
Abhängigkeit innerhalb des generischen Lambda, und jetzt kommen wir in einen Zustand, in dem es hypothetisch eine gültige Spezialisierung geben könnte, so dass wir nicht länger schlecht geformt sind, ndr.quelle