C++ Vector构造函数重载解析疑问及std::enable_if实现咨询
为什么
Vector<int>(3, 5)会调用第二个构造函数?如何用std::enable_if调整重载解析? 一、调用第二个构造函数的原因
先拆解两个构造函数的参数匹配逻辑:
- 构造函数1的签名是
Vector(size_t, int)(因为实例化时T=int),传入的3是int类型,需要隐式转换为size_t才能匹配第一个参数,5是int可直接匹配第二个参数。 - 构造函数2是模板构造函数,编译器会根据传入的参数推导模板参数
Iterator的类型:因为3和5都是int,所以Iterator被推导为int,此时构造函数2的签名为Vector(int, int),和传入的参数类型完全匹配,不需要任何隐式转换。
C++重载解析的核心规则是:完全匹配的函数重载优先级高于需要隐式转换的重载。因此编译器会优先选择构造函数2。
注意:全局定义的Iterator类和模板参数Iterator是完全独立的两个名字,编译器不会因为存在自定义Iterator类就限制模板参数的推导,依然会把int推导为模板参数的类型。
二、用std::enable_if调整重载解析的实现
我们需要借助SFINAE(替换失败不是错误)规则,让模板构造函数(构造函数2)仅在Iterator是真正的迭代器类型时才参与重载解析。当传入int这类非迭代器参数时,构造函数2会被自动排除,编译器就会选择构造函数1。
以下是实现代码:
#include <iostream> #include <type_traits> #include <iterator> class Iterator { public: Iterator(int &x): ptr_(&x) {} private: int* ptr_ = nullptr; }; template<class T> class Vector { public: Vector(size_t size, T default_value) { std::cout << "Constructor #1 called\n"; } // 仅当Iterator满足迭代器特征时,才启用该构造函数 template<class Iterator, typename = std::enable_if_t< // 排除与构造函数1参数类型冲突的情况 !std::is_same_v<T, Iterator> && // 验证Iterator是指向T类型的迭代器 std::is_convertible_v<typename std::iterator_traits<Iterator>::value_type, T> >> Vector(Iterator first, Iterator last) { std::cout << "Constructor #2 called\n"; } }; int main() { auto v = Vector<int>(3, 5); // 现在会调用构造函数1 // 验证迭代器版本仍可正常使用 int arr[] = {1,2,3}; auto v2 = Vector<int>(std::begin(arr), std::end(arr)); // 调用构造函数2 }
代码说明:
std::iterator_traits<Iterator>::value_type:只有真正的迭代器类型才会拥有这个成员,非迭代器类型(如int)会触发SFINAE,导致构造函数2被排除在重载候选之外。!std::is_same_v<T, Iterator>:避免当T与Iterator类型相同时(比如T=int且传入int参数),构造函数2的签名与构造函数1隐式转换后的签名产生冲突,确保只有迭代器类型能匹配构造函数2。
内容的提问来源于stack exchange,提问作者Amir Mokhammed-Ali
相关产品推荐
相关产品推荐

