I'm using Google Test v1.7
I've created a custom operator ==
which ASSERT_EQ
can't find, but which can be found if used directly. Here's the code
#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 );
}
The ASSERT_EQ( vec, deq )
line results in the following message from 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 );
^
while gcc 4.7.2 lists all of the templates it tried and failed to make expected == actual
work, ignoring the one I provided.
What I don't understand is why
ASSERT_EQ( vec, b )
finds the provided operator ==
; andvec == deq
compiles; butASSERT_EQ( vec, deq )
doesn't.Could someone please shine some light on this? It's got to be something blazingly obvious, but I can't see it.
Your problem is due to the ADL (argument dependent lookup). std::vector
and std::deque
, as you already know, are defined in std
namespace, but your are defining the operator==
at global namespace and ADL is failing to locate this function.
To solve your problem, you must define operator==
in the same namespace of your containers, that is inside std
namespace. The problem is that your are NOT ALLOWED to do that. In this way, I would suggest you to just change a bit of your approach. Why not try something like that:
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) );
}
The short answer:
The failure to find the correct operator==
template is primarily due to the fact that Google Test defines it's own operator==
template and the namespace lookup rule which does not use ADL chooses that template and rejects it. ADL, as pointed out by Amadeus, cannot hope to find the template that I defined.
The solution:
As Amadeus points out, moving things into the std
namespace (in this case to get ADL to work) is discouraged.
I have no qualms about polluting Google Test's namespace, so moving my template into ::testing::internals
solves the problem (using ordinary lookup, not ADL).
The longer answer:
My expectation was that the global operator==
should be discovered via what Vandevoorde & Josuttis, C++ Templates Section 9.2, p. 122, term ordinary lookup.
Here is code illustrating this:
#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) ;
}
This successfully compiles. My reading of Amadeus' answer is that Amadeus believes that should fail due to ADL. However, in this case ADL is not used to find operator==
. This can be demonstrated by explicitly turning off ADL in the call to the operator by rewriting
expected == actual
as
return (operator==)( expected, actual);
V&J Section 9.2.1, p.123:
ADL is also inhibited if the name of the function to be called is enclosed in parentheses
in which case the code still compiles.
In order to determine why the code involving Google Test failed, I performed rather extreme surgery upon the Google Test headers until I extracted just the code causing the compiler errors, which led to a definition of operator==
in the testing::internal
namespace in 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();
}
[...]
}
}
Translating that into my test code results in:
#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) ;
}
This successfully fails to compile with the unfound template errors. Of interest is the first message of failure:
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>’
So, it is first looking at A::operator==
.
Stroustrup, The C++ Programming Language, 4th Edition, Section 26.3.5 p. 753 states that the binding of dependent names is done by looking at
In this case, by the first rule, A::operator==
should be chosen rather than ::operator==
. ADL also fails to find ::operator==
because, as Amadeus points out, it is not in the std
namespace.
To convince myself that the compile failure is indeed the result of the first rule, I moved the definition of ::operator==
into the A
namespace and turned off ADL as before.
The code successfully compiles.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With