为何CTAD生成存储迭代器而非整数的vector?是否符合标准?
关于std::vector CTAD推导结果的疑问
下面的代码中,通过CTAD推导的std::vector对象v1,其元素类型被推导为迭代器;而显式指定<int>的v2元素类型为整数:
#include <boost/type_index.hpp> #include <iostream> #include <vector> int main() { std::vector<int> initv { 42, 31, 7 }; std::vector v1{initv.begin(), initv.end()}; // CTAD std::vector<int> v2{initv.begin(), initv.end()}; std::cout << boost::typeindex::type_id_with_cvr<decltype(v1)>().pretty_name() << std::endl; std::cout << boost::typeindex::type_id_with_cvr<decltype(v2)>().pretty_name() << std::endl; }
程序输出:
std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > > > std::vector<int, std::allocator<int> >
已知std::vector存在接收迭代器的构造函数,请问CTAD的这种推导结果是否正确?
回答
这个推导结果是正确的,核心原因是C++17类模板实参推导(CTAD)的重载决议规则:
当用花括号初始化v1时,编译器会优先匹配std::vector的initializer_list构造函数对应的推导指南,而非接收迭代器范围的构造函数。具体逻辑如下:
- 花括号内的两个参数是同类型的迭代器,编译器会尝试推导
std::vector<T>中的T为迭代器类型——因为std::initializer_list<T>要求所有元素为T类型,这里的两个迭代器正好符合该条件,因此最终推导出T为迭代器类型。 - 显式指定
<int>的v2则不会触发CTAD,编译器会直接匹配接收迭代器范围的构造函数,将迭代器指向的int元素拷贝到容器中。
如果想要让CTAD正确推导出std::vector<int>,只需把花括号换成圆括号初始化:
std::vector v1(initv.begin(), initv.end()); // 此时CTAD会推导出T为int
这种写法会让编译器匹配接收迭代器范围的构造函数对应的推导指南,从而得到预期的元素类型。
内容的提问来源于stack exchange,提问作者Tootsie
相关产品推荐
相关产品推荐

