jimporter / mettle

A C++20 unit test framework
https://jimporter.github.io/mettle
BSD 3-Clause "New" or "Revised" License
122 stars 12 forks source link

Compile error when applying METTLE_EXPECT macro to (std::string, Matcher) #23

Closed snizovtsev closed 8 years ago

snizovtsev commented 8 years ago

Minimal example:

suite<> test("", [](auto& _) {
    _.test("", []() {
        expect(std::string("42"), equal_to(std::string("42"))); // ok
        METTLE_EXPECT(std::string("42"), equal_to(std::string("42"))); // ambiguous call
    });
});

The error message is:

<skipped>:9:9: error: call to 'expect' is ambiguous
        METTLE_EXPECT(std::string("42"), equal_to(std::string("42"))); // ambiguous call
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<skipped>/include/mettle/matchers/expect.hpp:13:32: note: expanded from macro 'METTLE_EXPECT'
#    define METTLE_EXPECT(...) mettle::expect(                       \
                               ^~~~~~~~~~~~~~
<skipped>/include/mettle/suite/make_suite.hpp:58:5: note: in instantiation of function template
      specialization '(anonymous class)::operator()<mettle::suite_builder<mettle::expectation_error, const mettle::detail::auto_factory_t> >' requested here
    f(builder);
    ^
<skipped>/include/mettle/suite/make_suite.hpp:65:12: note: in instantiation of function template
      specialization 'mettle::detail::do_build<type, const mettle::detail::auto_factory_t &, (lambda at
      <skipped>:6:18)>' requested here
    return do_build<Builder, Args...>(name, attrs, auto_factory, f);
           ^
<skipped>/include/mettle/suite/make_suite.hpp:87:23: note: in instantiation of function template
      specialization 'mettle::detail::do_build<type, (lambda at <skipped>:6:18)>' requested here
    return make_array(do_build<Builder>(
                      ^
<skipped>/include/mettle/suite/make_suite.hpp:344:18: note: in instantiation of function template
      specialization 'mettle::detail::do_builds<Applied::type, (lambda at <skipped>:6:18)>' requested here
  return detail::do_builds<Applied::template type, Fixture...>(
                 ^
<skipped>/include/mettle/suite/global_suite.hpp:14:21: note: in instantiation of function template
      specialization 'mettle::make_basic_suites<mettle::expectation_error, (lambda at <skipped>:6:18)>' requested here
    auto &&suites = make_basic_suites<Exception, Fixture...>(
                    ^
<skipped>/include/mettle/suite/global_suite.hpp:27:7: note: in instantiation of function template
      specialization 'mettle::basic_suite<mettle::expectation_error>::basic_suite<(lambda at <skipped>:6:18)>'
      requested here
    : basic_suite(detail::all_suites(), name, attrs,
      ^
<skipped>/include/mettle/suite/global_suite.hpp:32:7: note: in instantiation of function template
      specialization 'mettle::basic_suite<mettle::expectation_error>::basic_suite<(lambda at <skipped>:6:18)>'
      requested here
    : basic_suite(name, {}, std::forward<Args>(args)...) {}
      ^
<skipped>:6:9: note: in instantiation of function template specialization
      'mettle::basic_suite<mettle::expectation_error>::basic_suite<(lambda at <skipped>:6:18)>' requested here
suite<> test("", [](auto& _) {
        ^
<skipped>/include/mettle/matchers/expect.hpp:29:6: note: candidate function [with T =
      std::__1::basic_string<char>, Matcher = mettle::basic_matcher<std::__1::basic_string<char>, std::__1::equal_to<void> >]
void expect(const T &value, const Matcher &matcher,
     ^
>>>>>>>>>> ERROR HERE
/<skipped>/include/mettle/matchers/expect.hpp:46:6: note: candidate function [with T =
      mettle::basic_matcher<std::__1::basic_string<char>, std::__1::equal_to<void> >, Matcher = mettle::detail::source_location]
<<<<<<<<<< 
void expect(const std::string &desc, const T &value, const Matcher &matcher,
     ^
1 error generated.

So, the compiler (clang version 3.7.1) was unable to choose between these two declarations:

template<typename T, typename Matcher>
void expect(const T &value, const Matcher &matcher,
            METTLE_SOURCE_LOCATION loc = METTLE_SOURCE_LOCATION::current());
template<typename T, typename Matcher>
void expect(const std::string &desc, const T &value, const Matcher &matcher,
            METTLE_SOURCE_LOCATION loc = METTLE_SOURCE_LOCATION::current());

The problem is at the second overload: desc matches as value, value as matcher and matcher as source location. To fix this some extra concept checking required here.

jimporter commented 8 years ago

Thanks for the bug report! I've pushed a fix to the master branch for this.

snizovtsev commented 8 years ago

The fix works for me, thank you!