C++类模板实参推导:该聚合推导指引为何被隐含生成?
聚合类模板参数推导的特殊情况解析
先看cppreference中给出的这段代码:
#include <tuple> #include <any> #include <string> template<class... Args> struct B : std::tuple<Args...>, Args... {}; B b{std::tuple<std::any, std::string>{}, std::any{}}; // 推导结果:b的类型为B<std::any, std::string>
你原本以为推导结果会是B<std::tuple<std::any, std::string>, std::any>,但实际却不是,核心原因要从聚合推导的规则说起:
- 聚合类的推导候选函数,参数列表是按顺序列出该聚合的所有公共基类和非静态数据成员的类型。
- 对于
B来说,它没有非静态成员,基类列表包含两部分:第一个基类是std::tuple<Args...>,后续是Args...展开后的每个独立类型(也就是每个Args元素都会成为一个基类)。
所以生成的推导候选函数签名是:
template<class... Args> B<Args...> F(std::tuple<Args...>, Args...);
现在看初始化过程的匹配逻辑:
- 第一个初始化器
std::tuple<std::any, std::string>{}会匹配候选函数的第一个参数std::tuple<Args...>,由此直接推导出Args...就是std::any, std::string。 - 第二个初始化器
std::any{}需要匹配候选函数的第二个参数(也就是Args...展开后的第一个元素std::any),完全匹配,推导有效。
如果按照你最初的思路,把两个初始化器对应到Args...的两个元素,那第一个基类会变成std::tuple<std::tuple<std::any, std::string>, std::any>,这和第一个初始化器的类型完全不匹配,这个推导候选会被编译器直接排除。编译器只会选择能让所有初始化器都匹配的推导结果,所以最终得到B<std::any, std::string>。
内容的提问来源于stack exchange,提问作者Ed Lim
相关产品推荐
相关产品推荐

