GTest的EXPECT_EQ为错误提供了未定义的参考

时间:2018-09-06 13:36:32

标签: c++ googletest

#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> ap2ArrayParam<5> ap3等)编写一个测试。

我遇到的错误:

〜/ tests.cpp.o:在函数ParamTest_SizeTest_Test::TestBody()': ~/tests.cpp: undefined reference to ArrayParam <3> :: _ length'collect2中:错误:ld返回1个退出状态

1 个答案:

答案 0 :(得分:2)

说明

通常,C ++中的静态数据成员需要在类外部进行定义,例如:

struct A {
static int myInt;
};
A::myInt; //doesn't even have to be initialized

常量和非易失性成员是特殊的,如in the reference所示。可以使用类体内的任何常量表达式对其进行初始化:

struct A {
static const int myInt = 1;
};

int main() {
    std::cout << A::myInt;
}

但是,此规则有一个例外(来自cppreference的同一段,重点是我的):

  

如果为常量 [非内联(自C ++ 17起)] 静态数据成员 [或constexpr   静态数据成员(自C ++ 11起)] odr-used,其定义为   名称空间范围仍然是必需的,但是它不能具有初始化程序。   对于constexpr数据成员,此定义已弃用(因为   C ++ 17)。

使用过的解释如下(强调我的意思):

  

非正式地,如果对象的值是 read(除非它是一个   编译时间常数)其地址已使用或   参考已绑定;如果使用了引用,则使用它,并且   在编译时未知其引用对象;并且功能被使用   如果对其进行了函数调用或采用了其地址。如果   使用对象,引用或函数,其定义必须   存在于程序中的某个位置;违反通常是   链接时错误。

这正是这里发生的情况。 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成员定义了 (您不仅不必使用它,而且实际上不应该使用它)。 / p>


如果不使用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 ++程序员都更容易理解和识别它。
作为大多数标准容器,它是高效的,并且由经验丰富的人精心编写。并且它已经被无数的程序员使用,并且经过您的测试和证明,很好。