Google Test无法找到用户提供的相等运算符

时间:2016-08-20 02:08:06

标签: c++ googletest

我正在使用Google Test v1.7

我创建了一个自定义updateAlert 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 ); } 行会产生Apple 6.0 clang的以下消息:

ASSERT_EQ( vec, deq )

虽然gcc 4.7.2列出了它尝试过但未能使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 ); ^ 工作的所有模板,忽略了我提供的模板。

我不明白是为什么

  • expected == actual找到提供的ASSERT_EQ( vec, b );和
  • operator ==编译;但
  • vec == deq没有。

有人可以对此有所启发吗?它必须是非常明显的东西,但我看不到它。

2 个答案:

答案 0 :(得分:4)

您的问题是由ADL(依赖于参数的查找)引起的。正如您所知,std::vectorstd::dequestd命名空间中定义,但您正在全局命名空间中定义operator==,并且ADL无法找到此函数。< / p>

要解决您的问题,您必须在容器的同一命名空间中定义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) );
}

答案 1 :(得分:1)

答案简短:

无法找到正确的operator==模板主要是因为Google Test定义了自己的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&#39;答案是Amadeus认为应该因ADL而失败。但是,在这种情况下,ADL 用于查找operator==。这可以通过重写

显式关闭对运算符的调用中的ADL来证明
expected == actual

作为

return (operator==)( expected, actual);

V&J第9.2.1节,第123页:

  

如果要调用的函数的名称括在括号中,也会禁止ADL

在这种情况下代码仍然可以编译。

为了确定涉及Google Test的代码失败的原因,我对Google Test标题执行了相当极端的手术,直到我只提取导致编译器错误的代码,从而导致operator==的定义{ {1}}中的{1}}命名空间:

testing::internal

将其翻译成我的测试代码会导致:

gtest/internal/gtest-linked_ptr.h

这成功无法使用未解决的模板错误进行编译。有趣的是失败的第一个信息:

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) ; }

Stroustrup, The C++ Programming Language, 4th Edition,第26.3.5节。 753指出依赖名称的绑定是通过查看

来完成的
  1. 定义模板时范围内的名称,加上
  2. 从属调用的参数名称空间中的名称
  3. 在这种情况下,根据第一条规则,应选择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==。 ADL也找不到A::operator==,因为正如Amadeus指出的那样,它不在::operator==命名空间中。

    为了说服自己编译失败确实是第一条规则的结果,我将::operator==的定义移到了std命名空间中,并像以前一样关闭了ADL。

    代码成功编译。