Google 测试找不到用户提供的相等运算符
Google Test can't find user provided equality operator
我正在使用 Google 测试版 v1.7
我创建了一个自定义operator ==
,ASSERT_EQ
找不到,但直接使用可以找到。这是代码
#include <vector>
#include <deque>
#include "gtest/gtest.h"
template< typename T> struct bar { T b; };
template< typename T>
bool operator == ( const std::vector<T>& v, const bar<T>& b ) { return false; }
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d) { return false; }
TEST( A, B ) {
std::vector<char> vec;
std::deque<char> deq;
bar<char> b;
// compiles
ASSERT_EQ( vec, b );
// compiles
vec == deq;
// doesn't compile
ASSERT_EQ( vec, deq );
}
ASSERT_EQ( vec, deq )
行导致来自 Apple 6.0 clang 的以下消息:
test/gtest.h:18861:16: error: invalid operands to binary expression ('const std::__1::vector<char, std::__1::allocator<char> >' and 'const
std::__1::deque<char, std::__1::allocator<char> >')
if (expected == actual) {
~~~~~~~~ ^ ~~~~~~
../x86_64-linux_debian-7/tests/gtest/gtest.h:18897:12: note: in instantiation of function template specialization 'testing::internal::CmpHelperEQ<std::__1::vector<char,
std::__1::allocator<char> >, std::__1::deque<char, std::__1::allocator<char> > >' requested here
return CmpHelperEQ(expected_expression, actual_expression, expected,
^
tst.cc:27:5: note: in instantiation of function template specialization 'testing::internal::EqHelper<false>::Compare<std::__1::vector<char, std::__1::allocator<char> >,
std::__1::deque<char, std::__1::allocator<char> > >' requested here
ASSERT_EQ( vec, deq );
^
虽然 gcc 4.7.2 列出了它尝试过但未能使 expected == actual
工作的所有模板,但忽略了我提供的模板。
我不明白的是为什么
ASSERT_EQ( vec, b )
找到提供的 operator ==
;和
vec == deq
编译;但是
ASSERT_EQ( vec, deq )
没有。
有人可以对此有所启发吗?它一定是非常明显的东西,但我看不到它。
您的问题是由于 ADL(参数相关查找)引起的。正如您所知,std::vector
和 std::deque
是在 std
命名空间中定义的,但是您在全局命名空间中定义了 operator==
并且 ADL 无法找到此函数。
要解决您的问题,您必须在容器的同一命名空间中定义 operator==
,即在 std
命名空间内。问题是您不允许这样做。通过这种方式,我建议你改变一下你的方法。为什么不尝试这样的事情:
template< typename T>
bool equal( const std::vector<T>& v , const std::deque<T>& d) { return false; }
TEST( A, B ) {
std::vector<char> vec;
std::deque<char> deq;
ASSERT_TRUE( equal(vec, deq) );
}
简答:
未能找到正确的 operator==
模板主要是因为 Google 测试定义了它自己的 operator==
模板和不使用 ADL 选择的名称空间查找规则该模板并拒绝它。正如Amadeus指出的那样,ADL无法找到我定义的模板。
解决方法:
正如 Amadeus 指出的那样,不鼓励将内容移动到 std
命名空间(在本例中是为了让 ADL 工作)。
我对污染 Google Test 的命名空间没有任何疑虑,因此将我的模板移动到 ::testing::internals
解决了问题(使用普通查找,而不是 ADL)。
较长的答案:
我的期望是全局 operator==
应该通过 Vandevoorde & Josuttis, C++ Templates 第 9.2 节,p. 发现。 122、术语普通查找。
这是说明这一点的代码:
#include <vector>
#include <deque>
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d);
namespace A {
template <typename T1, typename T2>
bool EQ( const T1& expected, const T2& actual ) {
return expected == actual;
}
}
void TestBody() {
std::vector<char> vec;
std::deque<char> deq;
::A::EQ(vec, deq) ;
}
编译成功。我对 Amadeus 的回答的解读是,Amadeus 认为应该因 ADL 而失败。但是,在这种情况下,ADL 是 而不是 用于查找 operator==
。这可以通过重写
在对运算符的调用中显式关闭 ADL 来证明
expected == actual
作为
return (operator==)( expected, actual);
V&J 第 9.2.1 节,第 123 页:
ADL is also inhibited if the name of the function to be called is enclosed in parentheses
在这种情况下,代码仍然可以编译。
为了确定涉及 Google 测试的代码失败的原因,我对 Google 测试 headers 进行了相当极端的手术,直到我只提取了导致编译器错误的代码,这导致在 gtest/internal/gtest-linked_ptr.h
:
的 testing::internal
命名空间中定义了 operator==
namespace testing {
namespace internal {
[...]
template<typename T> inline
bool operator==(T* ptr, const linked_ptr<T>& x) {
return ptr == x.get();
}
[...]
}
}
将其转换为我的测试代码会产生:
#include <vector>
#include <deque>
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d);
namespace A {
struct S {};
template<typename T> bool operator==(T* ptr, S& x);
template <typename T1, typename T2>
bool EQ( const T1& expected, const T2& actual ) {
return expected == actual;
}
}
void TestBody() {
std::vector<char> vec;
std::deque<char> deq;
::A::EQ(vec, deq) ;
}
编译失败,出现未找到的模板错误。感兴趣的是第一条失败消息:
gtst.cc: In instantiation of ‘bool A::EQ(const T1&, const T2&) [with T1 = std::vector<char>; T2 = std::deque<char>]’:
gtst.cc:25:21: required from here
gtst.cc:14:37: error: no matching function for call to ‘operator==(const std::vector<char>&, const std::deque<char>&)’
gtst.cc:14:37: note: candidates are:
gtst.cc:10:31: note: template<class T> bool A::operator==(T*, A::S&)
gtst.cc:10:31: note: template argument deduction/substitution failed:
gtst.cc:14:37: note: mismatched types ‘T*’ and ‘std::vector<char>’
所以,先看A::operator==
。
Stroustrup, The C++ Programming Language, 4th Edition,第 26.3.5 页。 753 声明依赖名称的绑定是通过查看
完成的
- 范围内的名称在定义模板的位置加上
- 从属调用的参数的名称空间中的名称
在这种情况下,根据第一条规则,应该选择 A::operator==
而不是 ::operator==
。 ADL 也无法找到 ::operator==
,因为正如 Amadeus 指出的那样,它不在 std
命名空间中。
为了说服自己编译失败确实是第一条规则的结果,我将 ::operator==
的定义移到了 A
命名空间中,并像以前一样关闭了 ADL。
代码编译成功。
我正在使用 Google 测试版 v1.7
我创建了一个自定义operator ==
,ASSERT_EQ
找不到,但直接使用可以找到。这是代码
#include <vector>
#include <deque>
#include "gtest/gtest.h"
template< typename T> struct bar { T b; };
template< typename T>
bool operator == ( const std::vector<T>& v, const bar<T>& b ) { return false; }
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d) { return false; }
TEST( A, B ) {
std::vector<char> vec;
std::deque<char> deq;
bar<char> b;
// compiles
ASSERT_EQ( vec, b );
// compiles
vec == deq;
// doesn't compile
ASSERT_EQ( vec, deq );
}
ASSERT_EQ( vec, deq )
行导致来自 Apple 6.0 clang 的以下消息:
test/gtest.h:18861:16: error: invalid operands to binary expression ('const std::__1::vector<char, std::__1::allocator<char> >' and 'const
std::__1::deque<char, std::__1::allocator<char> >')
if (expected == actual) {
~~~~~~~~ ^ ~~~~~~
../x86_64-linux_debian-7/tests/gtest/gtest.h:18897:12: note: in instantiation of function template specialization 'testing::internal::CmpHelperEQ<std::__1::vector<char,
std::__1::allocator<char> >, std::__1::deque<char, std::__1::allocator<char> > >' requested here
return CmpHelperEQ(expected_expression, actual_expression, expected,
^
tst.cc:27:5: note: in instantiation of function template specialization 'testing::internal::EqHelper<false>::Compare<std::__1::vector<char, std::__1::allocator<char> >,
std::__1::deque<char, std::__1::allocator<char> > >' requested here
ASSERT_EQ( vec, deq );
^
虽然 gcc 4.7.2 列出了它尝试过但未能使 expected == actual
工作的所有模板,但忽略了我提供的模板。
我不明白的是为什么
ASSERT_EQ( vec, b )
找到提供的operator ==
;和vec == deq
编译;但是ASSERT_EQ( vec, deq )
没有。
有人可以对此有所启发吗?它一定是非常明显的东西,但我看不到它。
您的问题是由于 ADL(参数相关查找)引起的。正如您所知,std::vector
和 std::deque
是在 std
命名空间中定义的,但是您在全局命名空间中定义了 operator==
并且 ADL 无法找到此函数。
要解决您的问题,您必须在容器的同一命名空间中定义 operator==
,即在 std
命名空间内。问题是您不允许这样做。通过这种方式,我建议你改变一下你的方法。为什么不尝试这样的事情:
template< typename T>
bool equal( const std::vector<T>& v , const std::deque<T>& d) { return false; }
TEST( A, B ) {
std::vector<char> vec;
std::deque<char> deq;
ASSERT_TRUE( equal(vec, deq) );
}
简答:
未能找到正确的 operator==
模板主要是因为 Google 测试定义了它自己的 operator==
模板和不使用 ADL 选择的名称空间查找规则该模板并拒绝它。正如Amadeus指出的那样,ADL无法找到我定义的模板。
解决方法:
正如 Amadeus 指出的那样,不鼓励将内容移动到 std
命名空间(在本例中是为了让 ADL 工作)。
我对污染 Google Test 的命名空间没有任何疑虑,因此将我的模板移动到 ::testing::internals
解决了问题(使用普通查找,而不是 ADL)。
较长的答案:
我的期望是全局 operator==
应该通过 Vandevoorde & Josuttis, C++ Templates 第 9.2 节,p. 发现。 122、术语普通查找。
这是说明这一点的代码:
#include <vector>
#include <deque>
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d);
namespace A {
template <typename T1, typename T2>
bool EQ( const T1& expected, const T2& actual ) {
return expected == actual;
}
}
void TestBody() {
std::vector<char> vec;
std::deque<char> deq;
::A::EQ(vec, deq) ;
}
编译成功。我对 Amadeus 的回答的解读是,Amadeus 认为应该因 ADL 而失败。但是,在这种情况下,ADL 是 而不是 用于查找 operator==
。这可以通过重写
expected == actual
作为
return (operator==)( expected, actual);
V&J 第 9.2.1 节,第 123 页:
ADL is also inhibited if the name of the function to be called is enclosed in parentheses
在这种情况下,代码仍然可以编译。
为了确定涉及 Google 测试的代码失败的原因,我对 Google 测试 headers 进行了相当极端的手术,直到我只提取了导致编译器错误的代码,这导致在 gtest/internal/gtest-linked_ptr.h
:
testing::internal
命名空间中定义了 operator==
namespace testing {
namespace internal {
[...]
template<typename T> inline
bool operator==(T* ptr, const linked_ptr<T>& x) {
return ptr == x.get();
}
[...]
}
}
将其转换为我的测试代码会产生:
#include <vector>
#include <deque>
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d);
namespace A {
struct S {};
template<typename T> bool operator==(T* ptr, S& x);
template <typename T1, typename T2>
bool EQ( const T1& expected, const T2& actual ) {
return expected == actual;
}
}
void TestBody() {
std::vector<char> vec;
std::deque<char> deq;
::A::EQ(vec, deq) ;
}
编译失败,出现未找到的模板错误。感兴趣的是第一条失败消息:
gtst.cc: In instantiation of ‘bool A::EQ(const T1&, const T2&) [with T1 = std::vector<char>; T2 = std::deque<char>]’:
gtst.cc:25:21: required from here
gtst.cc:14:37: error: no matching function for call to ‘operator==(const std::vector<char>&, const std::deque<char>&)’
gtst.cc:14:37: note: candidates are:
gtst.cc:10:31: note: template<class T> bool A::operator==(T*, A::S&)
gtst.cc:10:31: note: template argument deduction/substitution failed:
gtst.cc:14:37: note: mismatched types ‘T*’ and ‘std::vector<char>’
所以,先看A::operator==
。
Stroustrup, The C++ Programming Language, 4th Edition,第 26.3.5 页。 753 声明依赖名称的绑定是通过查看
完成的- 范围内的名称在定义模板的位置加上
- 从属调用的参数的名称空间中的名称
在这种情况下,根据第一条规则,应该选择 A::operator==
而不是 ::operator==
。 ADL 也无法找到 ::operator==
,因为正如 Amadeus 指出的那样,它不在 std
命名空间中。
为了说服自己编译失败确实是第一条规则的结果,我将 ::operator==
的定义移到了 A
命名空间中,并像以前一样关闭了 ADL。
代码编译成功。