以下代码无法在MSVC 2022和gcc 12.1(启用c++20)上编译,并出现相同的错误:
#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;
}
(**)
行生成一个错误,即无法推导param_type
ctor迭代器的类型:std::discrete_distribution<int>::param_type::param_type(_InIt,_InIt)': template parameter '_InIt' is ambiguous
为什么在两个编译器中推导这种迭代器类型都失败了?输出循环在相同的迭代器中工作正常。
如何解决这个问题?
1条答案
按热度按时间ybzsozfc1#
问题是C中的许多类型是在C20以前的范围范式下创建的,这意味着它们需要一对迭代器。
所有的视图和操作都是基于C20
std::ranges
范例来构造范围的。这意味着它们的范围可以由一个迭代器和一个表示结束的sentinel值来定义。sentinel * 不一定是 * 迭代器。对于v0
,它确实有一个不是迭代器的sentinel(这是因为iota
是一个基于sentinel的范围)。但是大多数在C20之前编写的类型在概念上消耗范围,仍然使用范围的成对迭代器模型。因此它们不能与任何使用哨兵的C++20范围一起工作。构造函数模板有一个类型跨越两个参数,但是你的
begin/end
参数是 * 不同的 * 类型。因此,它不能推导出一个类型。您需要通过
views::common
操作将此范围转换为容器或common_range
(使用成对迭代器的范围)。