std::initializer_list类型推导

8

最近我写了一个非常简单的类。

class C
{
public:
    void AddString(std::initializer_list<std::pair<const char*,int>> x)
    {
          //irrelevant
    }
};

int main()
 {
           C c;
           c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });
           .... //other unimportant stuff
           return 0;
 }

令我惊喜的是,它编译并且正常工作。请问有人能解释一下编译器是如何推断这些嵌套的大括号初始化是用于std::pair的吗?我使用的是MSVS 2013。

1个回答

9
c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });

您正在将一个自包含的大括号初始化列表作为参数传递给AddString函数,该列表本身包含嵌套的大括号初始化列表。如果内部的大括号初始化列表可以转换为std::pair<const char*,int>,则该参数可以匹配std::initializer_list<std::pair<const char*,int>>参数。

这种重载决议过程分为两步进行;首先尝试匹配以std::initializer_list参数为形参的std::pair构造函数。由于std::pair没有这样的构造函数,因此进行第二步,枚举使用char const[2]int作为实参的std::pair<const char*,int>其他构造函数。这将匹配以下pair构造函数,因为char const[2]隐式转换为char const *,而且构造函数本身不是explicit

template< class U1, class U2 >
constexpr pair( U1&& x, U2&& y );

引用 N3337 §13.3.1.7/1 [over.match.list]
当非聚合类类型 T 被列表初始化 (8.5.4) 时,重载决议会分为两个阶段来选择构造函数: - 首先,候选函数是类 T 的初始化列表构造函数 (8.5.4),参数列表只包含初始化列表作为单个参数。 - 如果没有可行的初始化列表构造函数,则再次进行重载决策,此时候选函数为类 T 的所有构造函数,参数列表由初始化列表中的元素组成。
如果初始化列表没有元素并且 T 有默认构造函数,则省略第一阶段。在复制列表初始化中,如果选择了一个显式构造函数,则初始化是不合法的。

非常好的答案,更加完整! - vsoftco
谢谢,这澄清了一些事情。当涉及到大括号初始化列表时,我需要更多地了解过载分辨率。 - pebbleonthebeach
@pebbleonthebeach 当涉及到列表初始化时,重载决议的规则就是我上面复制粘贴的内容。如果你的意思是需要了解一般的重载决议,我建议你从这个视频开始(如果你能找到时间,请观看整个系列)。 - Praetorian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接