I am not sure which compiler is right here, as I am not fully proficient with C++20 concepts yet. The following code is rejected by GCC (15.1) saying that there is no matching declaration for Foo::do_foo, Clang (20.1.0) accepts the code. Here it is on Godbolt. Replacing either decltype(x) with U in the return type, or using an unconstrained U for the function parameter makes both compilers happily compile the code. The idea was to for the return type to be a range of const T whenever the passed parameter is const.
Which compiler is "in the right" here? Or, alternatively, is the following correct C++?
#include <concepts>
#include <ranges>
#include <vector>
#include <iostream>
template<typename RangeType, typename ReturnType>
concept RangeReturnTypeIsConvertibleTo = requires(RangeType r) {
{ *r.begin() } -> std::convertible_to<ReturnType>;
};
template<typename R, typename V>
concept RangeOf = std::ranges::range<R> &&
RangeReturnTypeIsConvertibleTo<R, V>;
template<typename T, typename V>
concept IsQualificationOf = std::same_as<std::remove_cvref_t<T>, V>;
class Foo {
public:
using T = int;
template<IsQualificationOf<T> U>
auto do_foo(U&& x) -> RangeOf<std::remove_reference_t<decltype(x)>> auto;
};
template<IsQualificationOf<typename Foo::T> U>
auto Foo::do_foo(U&& x) -> RangeOf<std::remove_reference_t<decltype(x)>> auto
{
static std::vector<T> bar{4, 5, 8};
return bar;
}
int main() {
auto foo = Foo();
for(auto a : foo.do_foo(4)) std::cout << a << std::endl;
return 0;
}
GCC error:
<source>:31:6: error: no declaration matches 'auto [requires ::RangeOf<<placeholder>, typename std::remove_reference<decltype(Foo::do_foo::x)>::type>] Foo::do_foo(U&&)'
31 | auto Foo::do_foo(U&& x) -> RangeOf<std::remove_reference_t<decltype(x)>> auto
| ^~~
<source>:26:10: note: candidate is: 'template<class U> requires IsQualificationOf<U, int> auto [requires ::RangeOf<<placeholder>, typename std::remove_reference<decltype(Foo::do_foo::x)>::type>] Foo::do_foo(U&&)'
26 | auto do_foo(U&& x) -> RangeOf<std::remove_reference_t<decltype(x)>> auto;
| ^~~~~~
<source>:20:7: note: 'class Foo' defined here
20 | class Foo {
| ^~~
<source>: In function 'int main()':
<source>:42:28: error: use of 'auto [requires ::RangeOf<<placeholder>, typename std::remove_reference<decltype(Foo::do_foo::x)>::type>] Foo::do_foo(U&&) [with U = int]' before deduction of 'auto'
42 | for(auto a : foo.do_foo(4)) std::cout << a << std::endl;
| ~~~~~~~~~~^~~
Compiler returned: 1
intinstead ofFoo::TandUinstead ofdecltype(x)) passes.