C++:函数模板类型推导失败及参数传递推导为引用的疑问
问题分析与解决方案
一、模板参数T推导失败的原因
你定义的Uninitialized<T>是别名模板,C++编译器无法从Uninitialized<T>&这种别名类型反向推导出原始的T。因为别名模板只是类型的“别名”,并非独立的模板类型,编译器不会自动关联别名背后的模板参数——这就是必须显式指定<Obj>才能编译通过的核心原因。
二、为什么s被推导为const char*&
你的get_initialized函数参数用了万能引用Args&&... args,当传入左值(比如代码中的s是const char*类型的左值变量)时,万能引用的推导规则会将Args推导为const char*&(左值引用),这是C++标准规定的正常行为:万能引用会根据传入值的左右值属性调整推导结果。
三、解决方法
1. 修复模板参数T的推导问题
把Uninitialized从别名模板改成结构体模板,让编译器可以直接从结构体的类型参数推导T:
#include <type_traits> #include <string> template<typename T> struct Uninitialized { alignas(T) unsigned char storage[sizeof(T)]; }; // 也可以用std::aligned_storage_t作为成员: // template<typename T> // struct Uninitialized { // std::aligned_storage_t<sizeof(T), alignof(T)> storage; // }; template<typename T, typename... Args> T& get_initialized(Uninitialized<T>& storage, Args&&... args) { new (&storage.storage) T(std::forward<Args>(args)...); return reinterpret_cast<T&>(storage.storage); } // 测试代码 int main() { Uninitialized<std::string> obj; const char* s = "hello"; get_initialized(obj, s); // 现在可正常推导T为std::string }
如果坚持使用别名模板,也可以通过辅助模板提取T:
template<typename T> using Uninitialized = std::aligned_storage_t<sizeof(T), alignof(T)>; // 辅助模板:从Uninitialized<T>提取原始T template<typename T> struct ExtractTypeFromUninitialized; template<typename T> struct ExtractTypeFromUninitialized<Uninitialized<T>> { using type = T; }; template<typename Storage, typename... Args> auto get_initialized(Storage& storage, Args&&... args) -> typename ExtractTypeFromUninitialized<Storage>::type& { using T = typename ExtractTypeFromUninitialized<Storage>::type; new (&storage) T(std::forward<Args>(args)...); return reinterpret_cast<T&>(storage); }
2. 强制参数以拷贝方式传递
如果希望args始终以拷贝(值传递)的方式传递,有两种常见方式:
- 方式一:直接使用值传递参数
把函数参数从Args&&... args改成Args... args,无论传入左值还是右值,都会触发拷贝:template<typename T, typename... Args> T& get_initialized(Uninitialized<T>& storage, Args... args) { new (&storage) T(args...); // 传递拷贝后的参数 return reinterpret_cast<T&>(storage); } - 方式二:构造时强制拷贝
保持万能引用,但在构造T时用std::decay_t生成值类型,确保传递的是拷贝:template<typename T, typename... Args> T& get_initialized(Uninitialized<T>& storage, Args&&... args) { new (&storage) T(std::decay_t<Args>(std::forward<Args>(args))...); return reinterpret_cast<T&>(storage); }
内容的提问来源于stack exchange,提问作者Pozero
相关产品推荐
相关产品推荐

