如果您查看像std::ranges::fill
和std::ranges::generate
这样的标准算法,它们似乎都使用了额外的参数来推断其输出范围的范围值类型。例如,ranges::fill(v, 10)
由于其第二个自变量而能够推导出值类型T
。
然而,当您试图定义一个类似的函数,但去掉了第二个参数时,C++将无法再推导出值类型。例如,考虑以下函数:
template<typename T, std::output_range<const T&> R>
void ones(R && r)
{
for (T & value : r) {
value = 1;
}
}
如果您尝试在未明确指定值类型的情况下调用该代码,则该代码将不会编译:
std::array<int, 3> a;
// ones(a); // does not compile
ones<int>(a); // redundant!
当我试图编译注释掉的代码时,我得到了以下错误:
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp: In function ‘int main()’:
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp:19:9: error: no matching function for call to ‘ones(std::array<int, 3>&)’
19 | ones(a);
| ~~~~^~~
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp:9:6: note: candidate: ‘template<class T, class R> requires output_range<R, T> void ones(R&&)’
9 | void ones(R && r)
| ^~~~
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp:9:6: note: template argument deduction/substitution failed:
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp:19:9: note: couldn’t deduce template parameter ‘T’
19 | ones(a);
| ~~~~^~~
有没有什么方法可以推断出我缺少的范围值类型,或者这是不可能的?
听起来你想要:
template <typename T> requires std::output_range<T, std::ranges::range_value_t<T>>
或者,也许:
template <typename T> requires std::output_range<T, const std::ranges::range_value_t<T> &>
前者希望元素被移动,后者希望元素被复制。如果要同时支持这两种约束,则可以同时使用这两个约束。