#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和非易失性成员是特殊的,可以看出in the reference。它们可以使用类体内的任何常量表达式进行初始化:
struct A {
static const int myInt = 1;
};
int main() {
std::cout << A::myInt;
}
但是,这条规则有一个例外(来自cppreference中的同一段,强调我的):
如果const [非内联(自C ++ 17)]静态数据成员[或constexpr静态数据成员(自C ++ 11)]为odr-used,则仍需要命名空间作用域的定义,但它不能有初始化。 constexpr数据成员不推荐使用此定义(自C ++ 17起)。
odr-used被解释为(强调我的):
非正式地,如果一个对象的值被读取(除非它是一个编译时常量)或者被写入,它的地址被采用,或者一个引用被绑定到它上面,它就被使用了。如果使用引用并且在编译时不知道它的引用,则引用是odr-used;如果对函数进行了函数调用或者对其进行了地址处理,则函数会被使用。如果一个对象,一个引用或一个函数被使用,它的定义必须存在于程序的某个地方;违反此通常是链接时错误。
这正是这里发生的事情。 EXPECT_EQ
通过const T&
获取参数,即绑定对此类型的引用。并且由于引用绑定到_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 ++程序员识别。
作为大多数标准容器,它是高效的,并且由具有丰富经验的人员编写。并且经过测试并证明无数程序员在您之前使用它。