Reputation: 545
The following code fails to compile both on MSVC 2022 and gcc 12.1 (with c++20 enabled) with the same error:
#include <iostream>
#include <random>
#include <ranges>
#include <vector>
using namespace std;
int main()
{
auto v0 = views::iota(0) | views::take(5) | views::transform([](auto i) -> double { return 10.1 * double(i); });
// output: 0 10.1 20.2 30.3 40.4
// output: double
for (auto i = v0.begin(); i != v0.end(); ++i)
cout << *i << ' ';
cout << endl << typeid(decltype(*v0.begin())).name() << endl;
// error: template argument deduction failed
discrete_distribution<int>::param_type p0(v0.begin(), v0.end()); // (**)
// this is ok
vector<double> v1{10.1, 20.2, 30.3};
discrete_distribution<int>::param_type p1(v1.begin(), v1.end());
return 0;
}
The line (**)
generates an error that the type of the param_type
ctor iterators can not be deduced:
std::discrete_distribution<int>::param_type::param_type(_InIt,_InIt)': template parameter '_InIt' is ambiguous
Why does the deduction of this iterator type fail with both compiler? The output loop works fine with the same iterator.
How can this be fixed?
Upvotes: 1
Views: 184
Reputation: 473232
The problem is that many types in C++ were created under the pre-C++20 range paradigm. This means that they take a pair of iterators.
All of your views and operations construct ranges based on the C++20 std::ranges
paradigm. This means that their ranges can be defined by an iterator and a sentinel value representing the end. The sentinel does not have to be an iterator. And for the case of v0
, it does indeed have a sentinel that is not an iterator (this is because iota
is a sentinel-based range).
But most types that were written pre-C++20 which conceptually consume ranges still use the paired iterator model of ranges. So they cannot work with any C++20 range that uses a sentinel. The constructor template has one type across two parameters, but your begin/end
arguments are different types. Therefore, it fails to deduce the one type.
You will need to convert this range into either a container or a common_range
(a range using paired iterators) via the views::common
operation.
Upvotes: 4