Die EXPECT_NO_THROW
ein Makro wie folgt definiert ist:
#define EXPECT_NO_THROW(statement) \
GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
Wie Sie sehen, ist dies ein funktionsähnliches Makro, das ein Argument benötigt. Der Präprozessor (der sich mit Makros beschäftigt) arbeitet mit Token. Es versteht weder C++ noch C, sondern nur seine eigene Token-Sprache. (Heutzutage erfolgt das Kompilieren und Vorverarbeiten offensichtlich in einer Stufe, aber ich beziehe mich auf die Semantik der Präprozessorsprache.)
Der Präprozessor erwartet ein einzelnes Argument für EXPECT_NO_THROW
. Es trennt Argumente für funktionsähnliche Makros, indem es nach Kommas sucht.Also, wenn es eine Liste von Token in der Liste der Argumente für eine funktionsähnliche Makro sieht wie:
EXPECT_NO_THROW(const std::array<unsigned char, 16> foo = {1, 2, 3};)
dann trennt es die Argumentliste in Argumente wie folgt:
const std::array<unsigned char
16> foo = {1
2
3};
Und das sind natürlich mehrere Argumente, wo man für die Funktion wie Makro EXPECT_NO_THROW
erwartet wird.
Um mehrere Vorverarbeitung Token einschließlich ,
passieren als ein einziges Argument an eine funktionsähnlichen Makros, können Sie diese Tokens in Klammern setzen können:
EXPECT_NO_THROW((const std::array<unsigned char, 16> foo = {1, 2, 3};));
Dies wird jedoch nicht kompilieren:
Das EXPECT_NO_THROW
Makro wird wie folgt ergänzt:
#define GTEST_TEST_NO_THROW_(statement, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (::testing::internal::AlwaysTrue()) { \
try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
} \
catch (...) { \
goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
fail("Expected: " #statement " doesn't throw an exception.\n" \
" Actual: it throws.")
Wo der unerreichbaren Code Makro wie folgt definiert ist:
#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
if (::testing::internal::AlwaysTrue()) { statement; }
Also, wenn Sie eine Anweisung STMT
innerhalb des EXPECT_NO_THROW
Makro setzen, werden Sie am Ende mit:
if (::testing::internal::AlwaysTrue()) {
try {
if (::testing::internal::AlwaysTrue()) { STMT; };
}
// ...
Deshalb, wenn Sie setzen (STMT;)
in EXPECT_NO_THROW
, beenden Sie mit einem Line-up
if (::testing::internal::AlwaysTrue()) { (STMT;); };
Der Teil (STMT;);
ist n Rechtliches C++. Weder ist (STMT);
, wenn das STMT
eine Erklärung wie im OP ist.
Wenn Sie ({STMT;})
in das Makro übergeben, erhalten Sie am Ende ({STMT;});
, die in C++ immer noch illegal ist, aber in g ++ als Erweiterung zulässig ist; Es ist eine Ausdruck-Anweisung. Hier wird der {STMT;}
Teil als ein Ausdruck interpretiert, der in Klammern eingeschlossen ist, um den Ausdruck ({STMT;})
zu bilden.
Sie können auch versuchen, die Kommata zu isolieren. Wie in einem Kommentar zum OP auf Yakk hingewiesen, können Sie das Komma in der Template-Argumentenliste mit einem typedef verbergen; die restlichen Kommas in der Initialisierer-Liste kann unter Verwendung eines temporären, beispielsweise gewickelt werden:
using array_t = std::array<unsigned char, 16>;
EXPECT_NO_THROW(const array_t foo = (array_t{1, 2, 3}););
Während die ursprüngliche EXPECT_NO_THROW(STMT)
erlaubt STMT
eine Aussage, Aussagen in C++ sein kann nicht beliebig in Klammern gesetzt werden . Ausdrücke können jedoch beliebig in Klammern eingeschlossen werden, und Ausdrücke können als Anweisung verwendet werden. Aus diesem Grund funktioniert die Übergabe der Anweisung als Ausdruck-Anweisung.Wenn wir unsere Array-Deklaration als Ausdruck formulieren können, wird dies das Problem lösen:
EXPECT_NO_THROW((std::array<unsigned char, 16>{1, 2, 3}));
Hinweis dies ein temporäres Array erzeugt; Dies ist keine Deklarationsanweisung wie im OP, sondern ein einzelner Ausdruck.
Aber es ist vielleicht nicht immer so einfach, einen Ausdruck der Dinge zu erzeugen, die wir testen wollen. Im Standard C++ gibt es jedoch einen Ausdruck, der Anweisungen enthalten kann: Ein Lambda-Ausdruck.
EXPECT_NO_THROW(([]{ const std::array<unsigned char, 16> foo = {1, 2, 3}; }()));
Bitte beachten Sie die ()
nach dem Lambda was wichtig ist, um innerhalb der lamdba die Anweisung tatsächlich ausgeführt werden! Dies zu vergessen ist eine sehr subtile Quelle von Fehlern :(
Makros verstehen nicht C++, und vor allem '<,>' Vorlagen und Kommas innerhalb der Vorlage Argumente. Diese Kommas werden als mehrere Argumente für das Makro geparst. Als erster Durchgang, ' Verwenden Sie uchar_16_array = std :: array 'und verwenden Sie' uchar_16_array' im Makro Ich nehme an, dass es die Initialisierungsliste versteht (kann aber nicht garantieren) –
Yakk
Sie können einen anderen Satz Klammern verwenden, um das Problem zu umgehen Yakk erwähnt: 'EXPECT_NO_THROW ((...));' Dies wird jeden Code in der '...' als ein einziges Argument an das Makro übergeben. – dyp
@dyp, Leider sind die zusätzlichen Parens noch durchgeführt, so ist es möglich, dass sie den Ersatztext brechen, wenn das Makro sie nicht behandelt – chris