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

C++中声明不修改std::span的函数的最佳实践

如何通过函数类型区分修改/只读的std::span模板函数?

我有一批操作std::span的模板函数,部分函数会修改span指向的对象,另一部分则不会。我希望通过函数类型明确区分这两类函数,防止在只读函数中意外修改span。请问实现这一需求的最佳方式是什么?

无效方案示例

方案一:直接声明const版本的span参数

此方案会导致模板参数推导失败,无法直接传入非const的std::span:

#include <span>
#include <string>

using namespace std;

template<typename B> void want_span(std::span<B>) {};

template<typename B> void want_cspan(std::span<const B>) {};

int main()
{
  std::string r;
  want_span(std::span(r));  // OK
  want_cspan(std::span(r)); // 错误:无法推导B的类型
}

方案二:自定义cspan类型

自定义类型需要显式转换,且无法兼容原生std::span:

#include <span>
#include <string>
#include <ranges>

using namespace std;

template<typename B> struct cspan : std::span<const B> {
  using std::span<const B>::span;
};
template<std::ranges::contiguous_range R>
cspan(R &&) -> cspan<std::remove_const_t<std::ranges::range_value_t<R>>>;

template<typename B> void want_cspan2(cspan<B>) {};

int main()
{
  std::string r;
  want_cspan2(cspan(r)); // OK
  want_cspan2(std::span(r)); // 错误:无法匹配参数类型
}

最佳实践方案

方法1:重载+转发(兼容C++17及以上)

通过重载实现非conststd::span到const版本的自动转发,既保留函数类型的明确区分,又无需显式转换:

#include <span>
#include <string>

// 修改型函数:接受非const span,允许修改元素
template<typename B> void want_span(std::span<B>) {};

// 只读函数主版本:明确接受const span,保证只读
template<typename B> void want_cspan(std::span<const B>) {
    // 此处仅进行只读操作
};

// 重载:接受非const span,自动转发到const版本
template<typename B> void want_cspan(std::span<B> s) {
    want_cspan(std::span<const B>(s));
}

int main()
{
  std::string r;
  want_span(std::span(r));  // OK
  want_cspan(std::span(r)); // OK,自动转发到const版本
  want_cspan(r);            // 也可直接传入容器,推导为std::span<const char>
}

方法2:C++20 auto参数简化声明

利用C++20的auto模板参数,直接声明只读函数的参数为std::span<const auto>,自动支持非const span的隐式转换:

#include <span>
#include <string>

template<typename B> void want_span(std::span<B>) {};

// 只读函数:明确声明为const span,自动兼容非const span的隐式转换
void want_cspan(std::span<const auto> s) {
    // 此处仅进行只读操作
};

int main()
{
  std::string r;
  want_span(std::span(r));  // OK
  want_cspan(std::span(r)); // OK,隐式转换为std::span<const char>
  want_cspan(r);            // OK,直接推导为std::span<const char>
}

核心思路

  • 修改型函数使用std::span<B>作为参数,明确允许修改元素;
  • 只读型函数使用std::span<const B>作为参数,从类型层面保证不会意外修改元素;
  • 通过重载或C++20的auto参数,实现非const span到const span的自动转换,避免调用时的显式类型转换,保持代码简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:54:50