C++/doctest throws compiler warning when using namespaces

Viewed 28

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

This is an issue with doctest, see github-issue.

The workaround is to move the comparison operator into the same namespace, e.g.

namespace internal {
  bool operator==(const Bar& lhs, const Bar& rhs) {
    return lhs.i == rhs.i;
  }
}

Don't quite know how to handle the case if the arguments are defined in different namespaces...

Related