万能引用(Forward reference)改造:如何保留std::array类型约束?
问题描述
最简实现:
#include <array> #include <iostream> template <typename T> auto universal_ref(T&& arr) { for (auto && v : arr) std::cout << v << '\n'; } template <typename T, size_t N> auto not_universal_ref(std::array<T, N>&& arr) { for (auto && v : arr) std::cout << v << '\n'; }
技术问询:请说明可采用何种策略,将上述代码中的not_universal_ref函数改造为万能引用(Forward reference)形式,同时确保其参数必须为std::array类型?
解决方案
要实现万能引用+仅接受std::array的目标,核心需满足两个条件:
- 函数参数为模板参数的
T&&形式(万能引用的必要条件) - 通过类型约束,限制模板参数只能是
std::array的实例(包括左值引用和右值引用类型)
下面分两种C++版本给出具体实现策略:
策略一:C++20及以后(Concepts约束)
C++20引入的Concepts可以直观地对模板参数做类型约束,代码可读性最高:
步骤1:定义判断std::array的Concept
#include <array> #include <iostream> #include <type_traits> // 自定义Concept,判断类型是否为std::array的特化 template <typename T> concept StdArray = requires(T t) { typename T::value_type; typename T::size_type; // 验证类型本质是std::array requires std::same_as<std::decay_t<T>, std::array<typename std::decay_t<T>::value_type, std::decay_t<T>::size()>>; };
步骤2:改造not_universal_ref为万能引用+Concept约束
template <StdArray Arr> auto not_universal_ref(Arr&& arr) { for (auto && v : arr) std::cout << v << '\n'; }
这里Arr&&是万能引用,因为Arr是独立的模板参数;同时StdArray Concept确保了Arr只能是std::array的左值/右值实例。
策略二:C++17及以前(SFINAE技术)
在C++20之前,我们可以用SFINAE(替换失败并非错误)结合自定义类型 trait 来实现约束:
步骤1:自定义判断std::array的类型trait
#include <array> #include <iostream> #include <type_traits> // 基础模板:默认不是std::array template <typename T> struct is_std_array : std::false_type {}; // 特化模板:匹配std::array<T,N> template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type {}; // 辅助变量模板,简化使用(自动移除引用和cv限定符) template <typename T> constexpr bool is_std_array_v = is_std_array<std::decay_t<T>>::value;
步骤2:用enable_if实现SFINAE约束+万能引用
// 模板参数Arr是万能引用,enable_if仅当Arr是std::array时生效 template <typename Arr, typename = std::enable_if_t<is_std_array_v<Arr>>> auto not_universal_ref(Arr&& arr) { for (auto && v : arr) std::cout << v << '\n'; }
关键原理说明
- 万能引用的核心:只有当参数是模板参数的直接
T&&形式(如Arr&&,其中Arr是模板参数)时,才会触发万能引用的类型推导,既能接受左值也能接受右值。 - 原代码中的
std::array<T,N>&&是右值引用,不是万能引用——它只能接受std::array的右值实例,无法匹配左值。
内容的提问来源于stack exchange,提问作者deponovo
相关产品推荐
相关产品推荐

