I am using the C++ doctest framework for unit testing and stumbled upon an issue.
Whenever I try using the CHECK_EQ() macro for objects not in the general namespace I get compiler error messages.
This compiles fine (godbolt)
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest.h>
struct Foo {
int i;
};
bool operator==(const Foo& lhs, const Foo& rhs) { return lhs.i == rhs.i; }
TEST_CASE("Foo") {
const auto f0 = Foo{};
const auto f1 = Foo{};
CHECK(f0 == f1);
CHECK_EQ(f0, f1);
}
But moving the struct inside a namespace breaks the compilation (godbolt)
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest.h>
namespace internal {
struct Bar {
int i;
};
} // namespace internal
bool operator==(const internal::Bar& lhs, const internal::Bar& rhs) {
return lhs.i == rhs.i;
}
TEST_CASE("internal::Bar") {
const auto b0 = internal::Bar{};
const auto b1 = internal::Bar{};
CHECK(b0 == b1);
CHECK_EQ(b0, b1); // breaks code
}
The lengthy error messages:
In file included from <source>:3:
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h: In instantiation of 'bool doctest::detail::eq(const L&, const R&) [with L = internal::Bar; R = internal::Bar]':
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:1485:5: required from 'bool doctest::detail::RelationalComparator<0, L, R>::operator()(const L&, const R&) const [with L = internal::Bar; R = internal::Bar]'
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:1502:65: required from 'bool doctest::detail::ResultBuilder::binary_assert(const L&, const R&) [with int comparison = 0; L = internal::Bar; R = internal::Bar]'
<source>:19:3: required from here
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:1292:5: error: no match for 'operator==' (operand types are 'const internal::Bar' and 'const internal::Bar')
1292 | DOCTEST_RELATIONAL_OP(eq, ==)
| ^
In file included from <source>:3:
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:3583:6: note: candidate: 'bool doctest::operator==(const doctest::String&, const doctest::String&)'
3583 | bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; }
| ^~~~~~~~
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:3583:31: note: no known conversion for argument 1 from 'const internal::Bar' to 'const doctest::String&'
3583 | bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; }
| ~~~~~~~~~~~~~~^~~
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:3765:6: note: candidate: 'bool doctest::operator==(double, const doctest::Approx&)'
3765 | bool operator==(double lhs, const Approx& rhs) {
| ^~~~~~~~
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:3765:24: note: no known conversion for argument 1 from 'const internal::Bar' to 'double'
3765 | bool operator==(double lhs, const Approx& rhs) {
| ~~~~~~~^~~
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:3770:6: note: candidate: 'bool doctest::operator==(const doctest::Approx&, double)'
3770 | bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); }
| ^~~~~~~~
/opt/compiler-explorer/libs/doctest/trunk/doctest/doctest.h:3770:31: note: no known conversion for argument 1 from 'const internal::Bar' to 'const doctest::Approx&'
3770 | bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); }