c++ - GTest 的 EXPECT_EQ 给出未定义的错误引用

标签 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> 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/

相关文章:

c++ - 在 spoj 上解决 BRCKTS

c++ - 使用 Google Test 编译程序时出现 "g++ is not a full path"

c++ - 如何在 Google Test 中使用不同模板测试多个模板化类的相同行为?

c++ - Google 测试和 operator<< STL 类型的重载

c++ - 在Qt中测试Lambda唯一连接

c++ - 在Mysql C++ Connector中批量插入

c++ - 调用时 std::forward<Func> 的效用

c++ - 使用 pybind11 从 C++ 调用 Python 函数

c++ - 推力 set_intersection 是如何工作的?

c++ - gmock SetArgReferee : Set a non-copyable non-moveable object