You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否仅从范围参数推导C++输出范围的值类型?

问题:自定义范围函数如何自动推导值类型?

观察到std::ranges::fill和std::ranges::generate这类C标准算法可借助额外参数推导输出范围的值类型,例如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);   // 无法编译
ones<int>(a); // 冗余!

编译注释代码会得到如下错误:

/home/josiest/sandbox/cpp/template-template-range/sketch.cpp: 在函数‘int main()’中:
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp:19:9: 错误:找不到匹配的函数调用‘ones(std::array<int, 3>&)’
   19 |     ones(a);
      |     ~~~~^~~
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp:9:6: 注意:候选函数:‘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: 注意:   模板参数推导/替换失败:
/home/josiest/sandbox/cpp/template-template-range/sketch.cpp:19:9: 注意:   无法推导模板参数‘T’
   19 |     ones(a);
      |     ~~~~^~~

解决方案:从范围本身提取值类型

核心问题是原模板的参数顺序和约束写法错误——T无法从R直接推导,因为output_range<const T&> R的约束中T是未知的。要实现自动推导,需从范围R中提取其值类型,而非将T作为独立模板参数。

方法1:用std::ranges::range_value_t提取值类型

修改模板定义,移除独立的T参数,直接从R获取值类型:

template<std::output_range<R> R>
void ones(R && r)
{
    using T = std::ranges::range_value_t<R>;
    for (T & value : r) {
        value = 1;
    }
}

若需要更严谨的约束,确保范围能接受T类型赋值:

template<typename R>
requires std::output_range<R, std::ranges::range_value_t<R>>
void ones(R && r)
{
    using T = std::ranges::range_value_t<R>;
    for (T & value : r) {
        value = 1;
    }
}

此时调用ones(a)时,编译器会自动从std::array<int,3>推导出T=int,无需显式指定。

方法2:用auto简化循环变量

若无需显式命名T,可直接在循环中使用auto&,进一步简化代码:

template<std::output_range<R> R>
void ones(R && r)
{
    for (auto & value : r) {
        value = 1;
    }
}

这种写法中,编译器会自动推导循环变量类型为范围元素的引用类型,完全不需要手动指定T。

标准库算法的差异

像std::ranges::fill的签名为:

template<std::output_range<const T&> R>
constexpr void fill(R&& r, const T& value);

这里T可通过第二个参数value直接推导,因此无需从范围提取值类型。而你的场景没有额外参数,必须从范围本身获取值类型。

内容的提问来源于stack exchange,提问作者Josie Thompson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 05:40:38