Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ambiguous call to begin() when using CAPTURE #1882

Closed
jwdevel opened this issue Mar 11, 2020 · 2 comments
Closed

ambiguous call to begin() when using CAPTURE #1882

jwdevel opened this issue Mar 11, 2020 · 2 comments

Comments

@jwdevel
Copy link

jwdevel commented Mar 11, 2020

Describe the bug
I am using EASTL's fixed_vector in a test.
When I try to CAPTURE() the fixed_vector, I get a compile error due to ambiguity of begin(), when trying to evaluate Catch::is_range::value:

../../3rdparty/catch2/single_include/catch2/catch.hpp|1979 col 41| error: call of overloaded ‘begin(eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>)’ is ambiguous
             !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
                                    ~~~~~^~~~~~~~~~~~~~~~~~~

(full error below)

Expected behavior
I would expect the appropriate begin() to be chosen.
In this case, it would be: eastl::begin

Theorizing

I imagine this has to do with some subtlety of ADL, but I am not sure.

Perhaps eastl::begin is a candidate because the type is from that namespace, and std::begin is an equally-good candidate because this is being evaluated within std::is_same ?
Or maybe it is due to this catch2 code.

Note that other cases outside of Catch2 work fine, such as:

for (auto i : myvec) {
    //...
}

Though I know the rules for range-based for are a bit specialized, so maybe not the best example...

Reproduction steps

Nothing special with my setup; once you have EASTL and Catch2 set up, this will produce the error:

#include <EASTL/fixed_vector.h>
#include <catch2/catch.hpp>

SCENARIO("bug repro") {
    eastl::fixed_vector<int, 2, false> vec;
    CAPTURE(vec);
}

Platform information:

  • C++14
  • compiler: gcc (Debian 8.3.0-6) 8.3.0
  • Catch2 version: 2d172dc
  • OS: Debian 4.19.67-2

Additional context

Full error output:

In file included from tests/main/src/box.cpp:11:
../../3rdparty/catch2/single_include/catch2/catch.hpp: In instantiation of ‘const bool Catch::is_range<eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false> >::value’:
../../3rdparty/catch2/single_include/catch2/catch.hpp|2013 col 70| required by substitution of ‘template<class R> struct Catch::StringMaker<R, typename std::enable_if<(Catch::is_range<T>::value && (! Catch::Detail::IsStreamInsertable<T>::value))>::type> [with R = eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>]’
../../3rdparty/catch2/single_include/catch2/catch.hpp|1625 col 121| required from ‘std::__cxx11::string Catch::Detail::stringify(const T&) [with T = eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>; std::__cxx11::string = std::__cxx11::basic_string<char>]’
../../3rdparty/catch2/single_include/catch2/catch.hpp|2625 col 58| required from ‘void Catch::Capturer::captureValues(size_t, const T&) [with T = eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>; size_t = long unsigned int]’
tests/main/src/box.cpp|263 col 4| required from here
../../3rdparty/catch2/single_include/catch2/catch.hpp|1979 col 41| error: call of overloaded ‘begin(eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>)’ is ambiguous
             !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
                                    ~~~~~^~~~~~~~~~~~~~~~~~~
../../3rdparty/catch2/single_include/catch2/catch.hpp|1973 col 18| note: candidate: ‘Catch::not_this_one Catch::begin(...)’
     not_this_one begin( ... );
                  ^~~~~
In file included from /usr/include/c++/8/string:51,
                 from /usr/include/c++/8/stdexcept:39,
                 from /usr/include/c++/8/array:39,
                 from pu/include/pu/box.h:4,
                 from tests/main/src/box.cpp:1:
/usr/include/c++/8/bits/range_access.h|58 col 5| note: candidate: ‘decltype (__cont.begin()) std::begin(const _Container&) [with _Container = eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>; decltype (__cont.begin()) = const pu::Box<glm::vec<2, float, (glm::qualifier)0> >*]’
     begin(const _Container& __cont) -> decltype(__cont.begin())
     ^~~~~
In file included from ../../3rdparty/EASTL/include/EASTL/vector.h:39,
                 from ../../3rdparty/EASTL/include/EASTL/fixed_vector.h:16,
                 from pu/include/pu/box.h:8,
                 from tests/main/src/box.cpp:1:
../../3rdparty/EASTL/include/EASTL/iterator.h|1074 col 34| note: candidate: ‘decltype (container.begin()) eastl::begin(const Container&) [with Container = eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>; decltype (container.begin()) = const pu::Box<glm::vec<2, float, (glm::qualifier)0> >*]’
   EA_CPP14_CONSTEXPR inline auto begin(const Container& container) -> decltype(container.begin())
                                  ^~~~~

In file included from tests/main/src/box.cpp:11:
../../3rdparty/catch2/single_include/catch2/catch.hpp|1980 col 39| error: call of overloaded ‘end(eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>)’ is ambiguous
             !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
                                    ~~~^~~~~~~~~~~~~~~~~~~
../../3rdparty/catch2/single_include/catch2/catch.hpp|1974 col 18| note: candidate: ‘Catch::not_this_one Catch::end(...)’
     not_this_one end( ... );
                  ^~~
In file included from /usr/include/c++/8/string:51,
                 from /usr/include/c++/8/stdexcept:39,
                 from /usr/include/c++/8/array:39,
                 from pu/include/pu/box.h:4,
                 from tests/main/src/box.cpp:1:
/usr/include/c++/8/bits/range_access.h|78 col 5| note: candidate: ‘decltype (__cont.end()) std::end(const _Container&) [with _Container = eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>; decltype (__cont.end()) = const pu::Box<glm::vec<2, float, (glm::qualifier)0> >*]’
     end(const _Container& __cont) -> decltype(__cont.end())
     ^~~
In file included from ../../3rdparty/EASTL/include/EASTL/vector.h:39,
                 from ../../3rdparty/EASTL/include/EASTL/fixed_vector.h:16,
                 from pu/include/pu/box.h:8,
                 from tests/main/src/box.cpp:1:
../../3rdparty/EASTL/include/EASTL/iterator.h|1092 col 34| note: candidate: ‘decltype (container.end()) eastl::end(const Container&) [with Container = eastl::fixed_vector<pu::Box<glm::vec<2, float, (glm::qualifier)0> >, 4, false>; decltype (container.end()) = const pu::Box<glm::vec<2, float, (glm::qualifier)0> >*]’
   EA_CPP14_CONSTEXPR inline auto end(const Container& container) -> decltype(container.end())
@horenmar
Copy link
Member

horenmar commented Mar 24, 2020

Yeah, this is not really possible to fix, unless you make EASTL live in std and use it as the standard library in your code.

To exposit a bit, the problem is caused by mix of ADL, unconstrained templates and common idioms in generic code. As an example, the idiom to swap two instances of a generic T is this:

using std::swap;
swap(a, b);

This works by bringing in std::swap, which has a reasonable templated fallback implementation that works with any copyable/moveable type, and then it allows for ADL to find a specialized swap implementation for the concrete type of a and b. However, if the swap implementation found by ADL is not a better match (for example, if it is also a template), then you end up with ambiguous call, like in this example.


You are running into the same problem, but with begin and end.

@horenmar
Copy link
Member

There should be a workaround though, if you explicitly specialize Catch::is_range for EASTL containers, you should avoid the compilation error because there will be no need for the generic range check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants