One simple way of doing this prior to C 20 is to do a nested loop:
template<typename Container>
constexpr bool has_duplicate(Container&& container)
{
for (auto it1 = container.cbegin(); it1 != container.cend(); it1)
for(auto it2 = container.cbegin(); it2 != it1; it2)
if (*it1 == *it2)
return 1;
return 0;
}
With the addition of init-statement in range-based for loop, and the introduction of ranges::subrange
, I believe this function could be rewritten with range-based for loop:
template<std::ranges::input_range Container>
constexpr bool has_duplicate(Container&& container)
{
for(auto it = container.cbegin(); const auto& obj1 : container)
for(const auto& obj2 : std::ranges::subrange(container.cbegin(), it ))
if(obj1 == obj2)
return 1;
return 0;
}
While it worked fine on gcc, it fails to compile with clang, unless I manually set it with libc : https://godbolt.org/z/KM4a9zazs, with the following error:
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/12.0.0/../../../../include/c /12.0.0/bits/iterator_concepts.h:982:13: error: no matching function for call to '__begin'
= decltype(ranges::__cust_access::__begin(std::declval<_Tp&>()));
- Am I doing something wrong, or was it clang?
I've also tried:
template<std::ranges::input_range Container>
constexpr bool has_duplicate(Container&& container)
{
for(auto index = 0ull; const auto& obj1 : container)
for(const auto& obj2 : container | std::ranges::views::take(index ))
if(obj1 == obj2) return 1;
return 0;
}
Once again gcc worked with no problem, but clang failed with either libraries.
CodePudding user response:
Godbolt uses libstdc
by default, even when compiling with Clang, which is somewhat confusing.
Whether Clang should actually fully support linking towards libstdc
or not, I cannot say, but e.g. the following Clang bug report highlights the same issue:
Minimal example from the bug report:
#include <ranges> void foo() { std::ranges::iota_view iota(2, 10); iota.begin(); }
error: no matching function for call to '
__begin
'