为何std::vector的CTAD可同时接受int与double类型?
类模板实参推导(CTAD)下std::vector初始化的疑问
示例代码
#include <boost/type_index.hpp> #include <iostream> #include <vector> int main() { std::vector v{2, 3.14}; std::cout << boost::typeindex::type_id_with_cvr<decltype(v)>().pretty_name() << '\n'; std::cout << "size: " << v.size() << '\n'; for (auto x : v) std::cout << "- " << x << '\n'; }
输出结果
std::vector<double, std::allocator<double> > size: 2 - 2 - 3.14
问题描述
这段代码通过**类模板实参推导(CTAD)**实例化了std::vector。经确认此处调用了initializer_list构造函数,但为何它可同时接受int与double类型的元素,还能推导出vector<double>?若增加混合int与double的元素数量,编译会失败。
该现象在gcc与clang中结果一致:
$ g++ --version g++ (GCC) 13.0.1 20230401 (Red Hat 13.0.1-0) $ clang++ --version clang version 16.0.1 (Fedora 16.0.1-1.fc38)
原因解析
- 当使用初始化列表
{2, 3.14}进行CTAD推导时,编译器会尝试寻找一个能让所有元素隐式转换的共同类型T:这里int类型的2可以隐式转换为double,因此编译器推导出T=double,初始化列表被识别为initializer_list<double>,2会被自动转换为2.0存入容器,构造成功。 - 若增加元素后编译失败,本质是编译器无法确定唯一的共同类型
T:如果加入的元素类型无法通过隐式转换统一到同一类型(或是转换路径出现歧义),CTAD推导就会终止并报错。如果只是单纯增加int和double元素(如{2, 3.14, 5}),其实仍能推导出double类型;你遇到的编译失败场景,大概率是加入了其他无法与int/double统一转换的类型,或是触发了编译器推导规则中的边界限制。
内容的提问来源于stack exchange,提问作者Tootsie
相关产品推荐
相关产品推荐

