为什么要编译这段代码?
#include <string>
#include <variant>
#include <map>
void foo(std::map<int, std::variant<int, std::string>> map)
{}
int main()
{
foo({{1,"1"}, {2, 2}});
}我们有应该用来初始化std::map的{{1,"1"}, {2, 2}}对象。这可能与接受std::initializer_list & list-initialization的std::map ctor有关。但是我想知道{{1,"1"}, {2, 2}}到底是如何编译的?它有什么类型?在这种情况下,重载解析是如何工作的?
发布于 2021-01-21 21:48:33
首先,在您给出的示例中,没有重载解析。嗯,并不是说在重载方面有任何选择。要么只有一个函数匹配,要么不匹配;没有挑选顺序或模板,或者说到“重载解析”时通常意味着的任何复杂性。
编译器尝试将{{1,"1"}, {2, 2}}“映射”到std::map<int, std::variant<int, std::string>>的构造函数上,该构造函数将与std::map的std::initializer_list<std::pair<const int, std::variant<int, std::string>>构造函数(数字5 here,简而言之:映射元素的列表)一起工作,但前提是该列表中的每个元素都可以从嵌套部分构造。
这里,两个元素{1,"1"}和{2, 2}需要分别“映射”到一个std::pair<const int, std::variant<int, std::string>,使用std::pair的聚合初始化(这意味着你可以从一个带括号的初始化语句{t, u}构造一个代码,其中t是一个T,u是一个<代码>d14)。第二个参数更复杂,是一个<代码>d15。在这里,编译器可能使用演绎指南(尽管我认为这是一个实现细节)从它可能的替代类型之一构造<代码>d16对象。
可以在here上找到初始化的完整概述,尽管需要将几个部分放在一起才能得出上面的故事。请注意,这就是我对过程的理解,可能是在实际实现或标准中存在不同的细节,我认为这些细节在这里并不重要,甚至可能会阻碍对正在发生的事情的理解。
发布于 2021-01-23 01:58:32
你的代码可以归结为:
std::map<int, std::variant<int, std::string>> map = {{1,"1"}, {2, 2}};在这里,我们在对象的右边有一个带括号的初始化列表。这确实看了看左边,并找到了一个合适的构造函数。
它找到的是一个初始化器列表。
因此,上面的内容可以归结为:
std::initializer_list>> il = {{1,"1"},{2,2}};std::initializer_list
在这里,它将内部{}视为std::pair<const int, std::variant<int, std::string>,因此可以归结为:
std::pair<const int, std::variant<int, std::string>> one = {1,"1"};
std::pair<const int, std::variant<int, std::string>> two = {2,2};
工作中。这又可以归结为
std::variant<int,std::string> v1 = "1";
std::variant<int,std::string> v2 = 2;
工作,这最终归结为std::variant的构造函数做了一些SFINAE或需要魔法来挑选“正确的”构造函数。
https://stackoverflow.com/questions/65828553
复制相似问题