3

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.

Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39
  • Q: Please [edit] your post and copy/paste the clang compile and link lines. We need to know which clang [compiler options](https://clang.llvm.org/docs/ClangCommandLineReference.html) you're using. – paulsm4 Sep 30 '21 at 16:32
  • @paulsm4 compiler options are as-is in the godbolt link. I was using x86-64 trunk and no additional flags were used except `-stdc=c++20`. – Ranoiaetep Sep 30 '21 at 16:45

1 Answers1

5

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'

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
dfrib
  • 70,367
  • 12
  • 127
  • 192