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

如何为数组实现可同时接受左值和右值的转发引用?

问题

我正在学习C++泛型编程,试图解决如何为数组实现转发引用的问题。我已实现普通对象的完美转发:

template<typename T>
void do_something(T &&item) {...}

也实现了接受数组左值引用的模板函数:

template<typename T, unsigned int L>
void do_something(T (&arr)[L]) {...}

int main()
{
  int array[] = {1,2,3};
  do_something(array);
}

// works perfectly fine

以及接受数组右值的模板函数:

template<typename T, unsigned int L>
void do_something(T (&&arr)[L]) {...}

int main()
{
  do_something({1,2,3});
}

// also works

编译器能推导上述所有示例的类型。我原本以为最后一个函数可同时接受左值和右值(如第一个函数那样),但传入左值时编译器报错。请问是否存在无需重载,仅用单个模板函数即可同时接受数组左值和右值,且支持编译器类型推导的方法?


解答

你的问题核心在于:数组的右值引用模板T (&&arr)[L]并不是转发引用(universal reference)。普通对象的T&&能作为转发引用的前提是模板参数T是未修饰的推导类型,此时T&&会根据传入值的类别(左值/右值)折叠为对应的引用类型;而T (&&arr)[L]中的&&是绑定到数组类型的右值引用,只能匹配数组右值,无法兼容左值。

要实现单个模板同时接受数组左值和右值,只需要让模板参数直接推导整个数组的引用类型,再用T&&作为转发引用即可。具体写法如下:

#include <type_traits> // 用于数组类型相关的编译期工具

template<typename T>
void do_something(T&& arr) {
    // 提取数组的原始类型(去除引用修饰)
    using ArrayType = std::remove_reference_t<T>;
    // 可选:编译期检查,确保传入的是数组类型
    static_assert(std::is_array_v<ArrayType>, "Argument must be an array");
    
    // 获取数组长度和元素类型
    constexpr unsigned int Length = std::extent_v<ArrayType>;
    using ElementType = std::remove_extent_t<ArrayType>;
    
    // 示例操作:遍历数组,arr会保留原有的值类别(左值/右值)
    for (unsigned int i = 0; i < Length; ++i) {
        // 对arr[i]执行逻辑,比如打印
        // std::cout << arr[i] << " ";
    }
}

为什么这个写法有效?

  • 传入数组左值时,模板参数T会被推导为int(&)[3](以int array[3]为例),经过引用折叠后T&&等价于int(&)[3](左值引用),完美匹配左值数组。
  • 传入数组右值(比如临时数组{1,2,3})时,T会被推导为int(&&)[3],引用折叠后T&&等价于int(&&)[3](右值引用),匹配右值数组。

验证用法

int main() {
    // 左值数组
    int arr[] = {1,2,3};
    do_something(arr);
    
    // 右值临时数组
    do_something({4,5,6});
    
    return 0;
}

这个模板不仅能处理数组的完美转发,还兼容其他类型的转发(和你最初的普通对象转发模板功能一致),如果需要限制仅接受数组,可以保留static_assert的编译期检查。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 21:03:22