Gab*_*les 2 c++ macros templates googletest is-same
在使用 clang 编译器的 C++17 中,无论我这样做,我都会遇到相同的构建错误:
EXPECT_TRUE(std::is_same_v<decltype(var1), decltype(var2)>);
Run Code Online (Sandbox Code Playgroud)
或这个:
EXPECT_TRUE(typename std::is_same_v<decltype(var1), decltype(var2)>);,
Run Code Online (Sandbox Code Playgroud)
或这个:
EXPECT_TRUE(typename std::is_same_v<typename decltype(var1), typename decltype(var2)>);
Run Code Online (Sandbox Code Playgroud)
构建命令:
bazel test //my_target_dir:my_target
Run Code Online (Sandbox Code Playgroud)
构建错误:
Run Code Online (Sandbox Code Playgroud)error: too many arguments provided to function-like macro invocation decltype(var2)>); ^ gtest/gtest.h:1980:9: note: macro 'EXPECT_TRUE' defined here #define EXPECT_TRUE(condition) \ ^ myfile.cpp:125:5: error: use of undeclared identifier 'EXPECT_TRUE' EXPECT_TRUE(std::is_same_v< ^
请注意,Googletest 的定义EXPECT_TRUE()在这里:https://github.com/google/googletest/blob/master/googletest/include/gtest/gtest.h#L1980。
我正在做的事情有什么问题,我怎样才能编译它?
这不起作用,因为处理宏的 C++ 预处理器是在模板存在之前编写的,并且将逗号视为分隔宏的两个单独参数。它认为我已将EXPECT_TRUE()宏anything<foo作为第一个参数和bar>第二个参数调用:
// This does NOT work, because the preprocessor sees this 1 template
// argument to the macro as two separate arguments separated by the
// comma
EXPECT_TRUE(anything<foo, bar>);
Run Code Online (Sandbox Code Playgroud)
这些选项确实有效:
// Option 1: move the template outside of the macro call
bool isSameType = std::is_same_v<decltype(var1), decltype(var2)>;
EXPECT_TRUE(isSameType);
// Option 2: for this particular case I can instead use the
// `static_assert()` function in place of the `EXPECT_TRUE()` macro
static_assert(std::is_same_v<decltype(var1), decltype(var2)>);
// Option 3: use double parenthesis to force the macro to treat
// the parameter containing comma-separated template parameters
// as a **single argument** to the macro:
EXPECT_TRUE((std::is_same_v<decltype(var1), decltype(var2)>));
Run Code Online (Sandbox Code Playgroud)
在与一些朋友聊天一段时间后,其中一位名叫德鲁·格罗斯 (Drew Gross)的朋友解释了以下内容:
由于 C++ 预处理器模型,模板实例化中的逗号被解释为分隔宏的参数,而不是模板的参数。这是在现代 C++ 中强烈反对使用宏的众多原因之一。所以当你写:
Run Code Online (Sandbox Code Playgroud)SOME_MACRO(some_template<a, b>());它被解释为将 2 个参数传递给
SOME_MACRO,第一个是some_template<a,第二个是b>()。由于EXPECT_TRUE只接受一个参数,因此无法编译。在这种特殊情况下,我建议使用
static_assert而不是EXPECT_TRUE. 如果您要测试的东西不是编译时常量,则必须首先分配给局部变量,例如Run Code Online (Sandbox Code Playgroud)bool localVar = some_template<a, b>(); EXPECT_TRUE(localVar);
他说得一点都没错。由于 C 和 C++ 宏预处理器是在 C++ 存在之前编写的,因此它无法识别 C++<和>模板作用域符号(它认为它们分别只是“小于”和“大于”符号),因此在此语句中 ( EXPECT_TRUE(std::is_same_v<decltype(var1), decltype(var2)>);) ,它看到逗号并解析std::is_same_v<decltype(var1)为 gtestEXPECT_TRUE()宏的第一个参数,以及decltype(var2)>宏的第二个参数。
因此,解决方案如下:
bool isSameType = std::is_same_v<decltype(var1), decltype(var2)>;
EXPECT_TRUE(isSameType);
Run Code Online (Sandbox Code Playgroud)
然而,正如 Drew 所说,更好的解决方案是在这种情况下使用static_assert()gtest 而不是EXPECT_TRUE(),因为此测试可以在编译时而不是运行时完成:
(更好的解决方案):
static_assert(std::is_same_v<decltype(var1), decltype(var2)>);
Run Code Online (Sandbox Code Playgroud)
static_assert()注意: C++17 中不需要消息。看这里。
我做了一些额外的研究和实验,还发现额外的括号也可以解决这个问题。使用额外的括号会强制预处理器将整个输入参数识别为宏的 1 个参数,因为预处理器尊重括号,但根本不尊重模板<>符号,因为它不支持模板。
因此,这也有效:
EXPECT_TRUE((std::is_same_v<decltype(var1), decltype(var2)>));
Run Code Online (Sandbox Code Playgroud)
如果有疑问,请用括号括起来。如果需要的话,确实需要括号。:)
所以,现在我们有 3 个可行的解决方案来解决这个问题。static_assert()如果我需要在运行时测试一些模板输入,我可能会选择该选项作为我的主要解决方案,并将上面的额外括号选项作为我的解决方案。
一旦我知道问题的本质是什么(宏预处理器看到逗号并且不识别 C++ 模板<和>作用域运算符),我就能够进行一些谷歌搜索并找到以下答案来查看:
关键词:宏注意模板参数输入;C/C++ 宏预处理器的逗号参数分隔符,宏参数周围的宏中需要 C++ 额外的括号
| 归档时间: |
|
| 查看次数: |
5683 次 |
| 最近记录: |