能否无额外参数重载可变参数模板函数?vector匹配异常
为什么传入std::vector时总是触发可变参数模板重载?
当你调用Func("asd", v)时,编译器会对两个模板做重载决议,结果选可变参数版本的原因很明确:
- 可变参数模板
template <typename ... Args> std::string Func(std::string, Args &&...)靠转发引用特性,会把Args推导成std::vector<std::string>&,实例化出的函数是Func(std::string, std::vector<std::string>&)——这是精确匹配,不需要任何类型转换。 - 而你的vector专用模板
template <typename ArgType, typename Alloc> std::string Func(std::string, const std::vector<ArgType, Alloc> &)需要把非const的v绑定到const引用上,这得做一次const限定转换,属于不精确匹配。
C++重载决议规则里,精确匹配的候选函数优先级更高,所以编译器最终选了可变参数模板版本,这不是它识别不了vector特化,是匹配规则的问题。
解决办法有这几种:
办法1:让vector版本支持非const引用
把vector模板的参数改成非const引用,这样传入非const的v时,两个模板都能精确匹配,这时编译器会选更特化的vector版本:
template <typename ... Args> std::string Func(std::string, Args &&...); // 非const引用版本,匹配非const的vector template <typename ArgType = std::string, typename Alloc> std::string Func(std::string, std::vector<ArgType, Alloc> &); // 如果需要支持const vector,再加个const版本 template <typename ArgType = std::string, typename Alloc> std::string Func(std::string, const std::vector<ArgType, Alloc> &);
办法2:用SFINAE让可变参数模板避开vector
通过std::enable_if限制可变参数模板只在参数都不是vector的时候生效,这样传入vector时就只会匹配专用模板:
#include <type_traits> #include <vector> #include <string> // 辅助模板:判断类型是不是vector template <typename T> struct is_vector : std::false_type {}; template <typename T, typename Alloc> struct is_vector<std::vector<T, Alloc>> : std::true_type {}; // 可变参数模板:仅当所有参数都不是vector时启用 template <typename ... Args> std::enable_if_t<!(is_vector<std::decay_t<Args>>::value || ...), std::string> Func(std::string, Args &&...); // vector专用模板 template <typename ArgType = std::string, typename Alloc> std::string Func(std::string, const std::vector<ArgType, Alloc> &); int main() { std::vector<std::string> v; Func("asd", 1, 2.0f); // 调用可变参数版本 Func("asd", v); // 调用vector版本 }
办法3:C++20用概念约束
如果用C++20,用概念能更简洁地限制可变参数模板的参数:
#include <concepts> #include <vector> #include <string> template <typename T> concept NotVector = !std::same_as<std::decay_t<T>, std::vector<typename std::decay_t<T>::value_type, typename std::decay_t<T>::allocator_type>>; // 可变参数模板只接受非vector参数 template <NotVector ... Args> std::string Func(std::string, Args &&...); // vector专用模板 template <typename ArgType = std::string, typename Alloc> std::string Func(std::string, const std::vector<ArgType, Alloc> &);
内容的提问来源于stack exchange,提问作者noob_programmer
相关产品推荐
相关产品推荐

