如何解决MSVC无法推导模板模板参数的问题
解决MSVC模板模板参数推导失败问题
问题场景
MSVC存在非标准行为,导致某些情况下无法推导模板函数的模板模板参数,而相同代码在Clang和GCC中可正常编译。我们需要在不每次显式指定模板参数的前提下,让代码在MSVC中编译通过。
原代码问题
原代码中使用MyVec作为模板别名,MSVC无法将其正确推导为模板模板参数C,导致调用toRef(g)时提示“找不到匹配的重载函数”。
解决方案
方案一:避开模板模板参数推导,直接从容器类型提取信息
通过直接推导传入的容器类型,利用标准容器的value_type和rebind成员生成目标容器类型,完全绕开模板模板参数的推导问题:
#include <vector> #include <memory> template <typename T> using MyVec = std::vector<T>; template <typename T, template <class...> typename C> using Group = C<std::unique_ptr<T>>; template <typename T, template <class...> typename C> using GroupRef = C<T*>; template <typename Container> auto toRef(const Container& arg) { // 从容器的value_type中提取unique_ptr指向的类型T using ValueType = typename Container::value_type; using T = typename ValueType::element_type; // 用rebind生成对应T*的容器类型 using TargetContainer = typename Container::template rebind<T*>::other; TargetContainer result; for (const auto& p : arg) { result.push_back(p.get()); } return result; } int main() { Group<int, MyVec> g; auto x = toRef(g); // MSVC、Clang、GCC均可正常编译 }
方案二:放宽模板模板参数的匹配约束
允许模板模板参数C携带额外的模板参数(比如std::vector的分配器参数),让MSVC能正确匹配模板别名:
#include <vector> #include <memory> template <typename T> using MyVec = std::vector<T>; template <typename T, template <class...> typename C> using Group = C<std::unique_ptr<T>>; template <typename T, template <class...> typename C> using GroupRef = C<T*>; // 允许C携带额外的模板参数(如allocator) template <typename T, template <class...> typename C, typename... Args> GroupRef<T, C> toRef(const C<std::unique_ptr<T>, Args...>& arg) { GroupRef<T, C> result; for (const auto& p : arg) { result.push_back(p.get()); } return result; } int main() { Group<int, MyVec> g; auto x = toRef(g); // 所有编译器均可正常编译 }
原理说明
- 方案一:通过直接操作具体容器类型的关联类型(
value_type、rebind),不需要依赖模板模板参数的推导,兼容性最强,适用于所有标准容器。 - 方案二:通过可变模板参数
Args...匹配容器的额外模板参数,让模板别名MyVec能被正确识别为std::vector的实例,解决MSVC的推导缺陷。
内容的提问来源于stack exchange,提问作者typ1232
相关产品推荐
相关产品推荐

