I am trying to write a generic reverse wrapper for containers that use bidirectional iterators using std::reverse_iterator
.
However, it would seem that when the compiler looks for begin(...)
or end(...)
, it'll say it can't find a matching function call to reverse_wrapper<CONTAINER>::begin(container)
because the candidate expects 0 arguments, but 1 provided.
I would have guessed this is because std::begin(myArray&)
and std::end(myArray&)
don't exist. Forcing them into the std
namespace didn't work (and is not advisable anyway). I've also tried to remove the std::
prefixes from my reverse_wrapper
but that didn't work and would also break the working std
container implementation.
This seems to be a scope resolution problem, but I can't seem to get the fix. What am I doing wrong?
Code:
#include <iterator>
#include <iostream>
#include <vector>
#define Fn1 0 // std container WORKS
#define Fn2 1 // non-std container DOESN'T WORK
template <typename Container>
struct reverse_wrapper
{
Container& container;
auto begin()
-> std::reverse_iterator< decltype(std::end(container)) >
{
return std::reverse_iterator< decltype(std::end(container)) >(std::end(container));
}
auto end()
-> std::reverse_iterator< decltype(std::begin(container)) >
{
return std::reverse_iterator< decltype(std::begin(container)) >(std::begin(container));
}
};
template <typename Container>
auto reverse(Container&& container)
-> reverse_wrapper<Container>
{
return{ container };
}
struct myArray
{
int elements[5] = {1,2,3,4,5};
};
int* begin(myArray& array) { return &array.elements[0]; }
int* end(myArray& array) { return &array.elements[5]; }
#if Fn1
void fn1()
{
std::vector<int> x = { 1,2,3,4,5 };
for (auto& ix : reverse(x))
{
std::cout << ix << std::endl;
}
std::cout << "-----" << std::endl;
for (auto& ix : x)
{
std::cout << ix << std::endl;
}
}
#endif
#if Fn2
void fn2()
{
myArray x;
for (auto& ix : reverse(x))
{
std::cout << ix << std::endl;
}
std::cout << "-----" << std::endl;
for (auto& ix : x)
{
std::cout << ix << std::endl;
}
}
#endif
int main()
{
#if Fn1
fn1();
#endif
#if Fn2
fn2();
#endif
}
Errors:
In instantiation of 'struct reverse_wrapper': 61:30: required from here 14:56: error: no matching function for call to 'end(myArray&)' 14:56: note: candidates are: In file included from /usr/include/c++/4.9/string:51:0, from /usr/include/c++/4.9/bits/locale_classes.h:40, from /usr/include/c++/4.9/bits/ios_base.h:41, from /usr/include/c++/4.9/ios:42, from /usr/include/c++/4.9/ostream:38, from /usr/include/c++/4.9/iterator:64, from 1: /usr/include/c++/4.9/bits/range_access.h:68:5: note: template decltype (__cont.end()) std::end(_Container&) end(_Container& __cont) -> decltype(__cont.end()) ^ /usr/include/c++/4.9/bits/range_access.h:68:5: note: template argument deduction/substitution failed: /usr/include/c++/4.9/bits/range_access.h: In substitution of 'template decltype (__cont.end()) std::end(_Container&) [with _Container = myArray]': 14:56: required from 'struct reverse_wrapper' 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:68:5: error: 'struct myArray' has no member named 'end' In instantiation of 'struct reverse_wrapper': 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:78:5: note: template decltype (__cont.end()) std::end(const _Container&) end(const _Container& __cont) -> decltype(__cont.end()) ^ /usr/include/c++/4.9/bits/range_access.h:78:5: note: template argument deduction/substitution failed: /usr/include/c++/4.9/bits/range_access.h: In substitution of 'template decltype (__cont.end()) std::end(const _Container&) [with _Container = myArray]': 14:56: required from 'struct reverse_wrapper' 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:78:5: error: 'const struct myArray' has no member named 'end' In instantiation of 'struct reverse_wrapper': 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:97:5: note: template _Tp* std::end(_Tp (&)[_Nm]) end(_Tp (&__arr)[_Nm]) ^ /usr/include/c++/4.9/bits/range_access.h:97:5: note: template argument deduction/substitution failed: 14:56: note: mismatched types '_Tp [_Nm]' and 'myArray' In file included from /usr/include/c++/4.9/bits/basic_string.h:42:0, from /usr/include/c++/4.9/string:52, from /usr/include/c++/4.9/bits/locale_classes.h:40, from /usr/include/c++/4.9/bits/ios_base.h:41, from /usr/include/c++/4.9/ios:42, from /usr/include/c++/4.9/ostream:38, from /usr/include/c++/4.9/iterator:64, from 1: /usr/include/c++/4.9/initializer_list:99:5: note: template constexpr const _Tp* std::end(std::initializer_list) end(initializer_list __ils) noexcept ^ /usr/include/c++/4.9/initializer_list:99:5: note: template argument deduction/substitution failed: 14:56: note: 'myArray' is not derived from 'std::initializer_list' 20:58: error: no matching function for call to 'begin(myArray&)' 20:58: note: candidates are: In file included from /usr/include/c++/4.9/string:51:0, from /usr/include/c++/4.9/bits/locale_classes.h:40, from /usr/include/c++/4.9/bits/ios_base.h:41, from /usr/include/c++/4.9/ios:42, from /usr/include/c++/4.9/ostream:38, from /usr/include/c++/4.9/iterator:64, from 1: /usr/include/c++/4.9/bits/range_access.h:48:5: note: template decltype (__cont.begin()) std::begin(_Container&) begin(_Container& __cont) -> decltype(__cont.begin()) ^ /usr/include/c++/4.9/bits/range_access.h:48:5: note: template argument deduction/substitution failed: /usr/include/c++/4.9/bits/range_access.h: In substitution of 'template decltype (__cont.begin()) std::begin(_Container&) [with _Container = myArray]': 20:58: required from 'struct reverse_wrapper' 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:48:5: error: 'struct myArray' has no member named 'begin' In instantiation of 'struct reverse_wrapper': 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:58:5: note: template decltype (__cont.begin()) std::begin(const _Container&) begin(const _Container& __cont) -> decltype(__cont.begin()) ^ /usr/include/c++/4.9/bits/range_access.h:58:5: note: template argument deduction/substitution failed: /usr/include/c++/4.9/bits/range_access.h: In substitution of 'template decltype (__cont.begin()) std::begin(const _Container&) [with _Container = myArray]': 20:58: required from 'struct reverse_wrapper' 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:58:5: error: 'const struct myArray' has no member named 'begin' In instantiation of 'struct reverse_wrapper': 61:30: required from here /usr/include/c++/4.9/bits/range_access.h:87:5: note: template _Tp* std::begin(_Tp (&)[_Nm]) begin(_Tp (&__arr)[_Nm]) ^ /usr/include/c++/4.9/bits/range_access.h:87:5: note: template argument deduction/substitution failed: 20:58: note: mismatched types '_Tp [_Nm]' and 'myArray' In file included from /usr/include/c++/4.9/bits/basic_string.h:42:0, from /usr/include/c++/4.9/string:52, from /usr/include/c++/4.9/bits/locale_classes.h:40, from /usr/include/c++/4.9/bits/ios_base.h:41, from /usr/include/c++/4.9/ios:42, from /usr/include/c++/4.9/ostream:38, from /usr/include/c++/4.9/iterator:64, from 1: /usr/include/c++/4.9/initializer_list:89:5: note: template constexpr const _Tp* std::begin(std::initializer_list) begin(initializer_list __ils) noexcept ^ /usr/include/c++/4.9/initializer_list:89:5: note: template argument deduction/substitution failed: 20:58: note: 'myArray' is not derived from 'std::initializer_list' In function 'void fn2()': 61:30: error: invalid initialization of reference of type 'myArray&' from expression of type 'reverse_wrapper' 38:6: note: in passing argument 1 of 'int* begin(myArray&)' 61:30: error: invalid initialization of reference of type 'myArray&' from expression of type 'reverse_wrapper' 39:8: note: in passing argument 1 of 'int* end(myArray&)'
std::
instd::begin
andstd::end
, then addusing std::begin; using std::end
in the places where you usebegin
andend
. It might be better to use automatically deduced returned type instead of trailing return type in some cases – KABoissonneaultusing std::begin/end
, but it won't work at class scope so the return type can't find it. I also thought of using an automatically deduced type, but that doesn't work in VS2013. – AdrianmyArray
is just a placeholder for other array implementations scattered around, some at the base scope, some instd
. – AdrianmyArray
should provide its own iterators, and thenreverse_wrapper
can simply delegate to the container without usingreverse_iterator
directly:template <typename Container> struct reverse_wrapper { Container& container; auto begin() { return std::rbegin(container); } auto end() { return std::rend(container); } };
– Remy Lebeau