#include <gtest/gtest.h>
template<typename T, size_t N>
size_t getSize(T (&arr)[N]){
return N;
}
template<int N>
struct ArrayParam {
static const int _length = N;
int _arr[N];
};
ArrayParam<3> ap1 = {{1,2,3}};
//ArrayParam<4> ap2 = {{1,2,3,4}};
class ParamTest: public ::testing::TestWithParam<ArrayParam<3>>{};
TEST_P(ParamTest, SizeTest){
ArrayParam<3> param = GetParam();
printf("\nparam._length == %d\n",param._length); //OK
printf("\nValue2 == %d\n",ArrayParam<3>::_length); //OK
//EXPECT_EQ(param._length,getSize(param._arr)); //NOT OK
//EXPECT_EQ(3,param._length); // NOT OK
EXPECT_EQ(3,sizeof(param._arr)/sizeof(int)); //OK
}
INSTANTIATE_TEST_CASE_P(ArraySize,ParamTest,testing::Values(ap1));
有人知道为什么当我尝试访问 _length
时 EXPECT_EQ 不能作为 printf 工作吗? ?
我的最终目标是为各种 ArrayParam<T>
编写单个测试实例对象,例如 ArrayParam<4> ap2
, ArrayParam<5> ap3
, 等等。
我得到的错误:
~/tests.cpp.o: 在函数中ParamTest_SizeTest_Test::TestBody()': ~/tests.cpp: undefined reference to
ArrayParam<3>::_length' collect2: error: ld 返回 1 退出状态
最佳答案
解释
一般来说,C++中的静态数据成员需要在类外定义,像这样:
struct A {
static int myInt;
};
A::myInt; //doesn't even have to be initialized
Const和non-volatile成员比较特殊,可见in the reference .它们可以用类主体中的任何常量表达式进行初始化:
struct A {
static const int myInt = 1;
};
int main() {
std::cout << A::myInt;
}
但是,这条规则有一个异常(exception)(来自 cppreference 中的同一段,强调我的):
If a const [non-inline (since C++17)] static data member [or a constexpr static data member (since C++11)] is odr-used, a definition at namespace scope is still required, but it cannot have an initializer. This definition is deprecated for constexpr data members (since C++17).
odr-used 是这样解释的(强调我的):
Informally, an object is odr-used if its value is read (unless it is a compile time constant) or written, its address is taken, or a reference is bound to it; a reference is odr-used if it is used and its referent is not known at compile time; and a function is odr-used if a function call to it is made or its address is taken. If an object, a reference or a function is odr-used, its definition must exist somewhere in the program; a violation of that is usually a link-time error.
这正是这里发生的事情。 EXPECT_EQ
通过 const T&
获取参数,即绑定(bind)一个引用到这个类型。由于引用绑定(bind)到 _length
,它使其成为 odr-used
并且需要类外成员定义。
odr-used
异常不适用于 printf
,因为 printf
(作为 C 函数)不采用引用。它属于定义的“读取(除非它是编译时常量)”部分。由于我们有一个编译时间常量,所以一切正常。
解决方案
如果您使用的是 C++17,只需将 const
更改为 constexpr
即可:
template<int N>
struct ArrayParam<N> {
static constexpr int _length = N;
int _arr[N];
};
C++17 标准为命名空间范围内的 constexpr static
成员定义已弃用(你不仅不必使用它,实际上你不应该使用它)。
如果您不使用 C++17,则必须在与该类相同的命名空间中添加此数据成员的定义:
template<int N>
struct ArrayParam<N> {
static constexpr int _length = N; //const is fine as well
int _arr[N];
};
template<int N>
constexpr int ArrayParam<N>::_length;
这将允许您将它与 GoogleTest 的 EXPECT_EQ
作为旁注,我想推荐再次使用 std::array
。它更具可读性,更容易被所有 C++ 程序员识别。
作为大多数标准容器,它是高效的,并且由经验丰富的人编写得很好。在您之前使用它的无数程序员已经过测试并证明它很好。
关于c++ - GTest 的 EXPECT_EQ 给出未定义的错误引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52205340/