如何从同构模板参数的完美转发函数中提取模板类型?
解决方案
你可以利用C++20的模板参数推导和完美转发特性,通过提取第一个参数的类型自动确定std::vector的元素类型,同时确保所有传入参数类型一致。以下是实现代码:
#include <vector> #include <utility> #include <type_traits> template <typename T> struct Object { T x {}; }; // 核心工厂函数实现 template <typename ObjType, typename... Args> auto make_objects(ObjType&& first, Args&&... args) { // 提取第一个参数的原始类型(移除引用、const/volatile限定符) using ElementType = std::remove_cvref_t<ObjType>; std::vector<ElementType> vec; vec.reserve(1 + sizeof...(args)); // 预留空间减少扩容开销 // 完美转发所有参数,用emplace_back构造元素 vec.emplace_back(std::forward<ObjType>(first)); (vec.emplace_back(std::forward<Args>(args)), ...); return vec; } // 测试代码 int main() { Object<int> x1 {1}; Object<int> x2 {2}; auto collection = make_objects(x1, x2, Object<int>(3)); // collection 类型为 std::vector<Object<int>>,包含三个元素的副本 }
关键细节说明
- 类型推导逻辑:通过
std::remove_cvref_t<ObjType>获取第一个参数的纯类型(剥离引用、const、volatile修饰),以此作为vector的元素类型,避免显式指定模板参数。 - 完美转发实现:使用
std::forward保留每个参数的值类别(左值/右值),让emplace_back自动选择拷贝或移动构造,最大化性能。 - 参数包展开:通过C++17引入的折叠表达式
(vec.emplace_back(...), ...)遍历所有可变参数,逐个添加到vector中。 - 隐式类型检查:如果传入不同类型的参数(比如混合
Object<int>和Object<double>),编译器会在emplace_back阶段报错,因为vector只能接受同类型元素。
编译期强制类型一致(可选优化)
如果需要在编译期就明确抛出类型不匹配的错误,可以添加静态断言:
template <typename ObjType, typename... Args> auto make_objects(ObjType&& first, Args&&... args) { using ElementType = std::remove_cvref_t<ObjType>; // 强制所有参数的原始类型与第一个参数一致 static_assert((std::same_as<std::remove_cvref_t<Args>, ElementType> && ...), "All arguments must be of the same type"); std::vector<ElementType> vec; vec.reserve(1 + sizeof...(args)); vec.emplace_back(std::forward<ObjType>(first)); (vec.emplace_back(std::forward<Args>(args)), ...); return vec; }
内容的提问来源于stack exchange,提问作者davidA
相关产品推荐
相关产品推荐

