编译器如何在vector和initializer_list之间做出决定?

时间:2017-03-05 20:37:31

标签: c++ c++11 vector initialization

在下面的代码中,当出现两种版本的print方法时,第一个调用将解析为具有initializer_list的调用。如果我用initializer_list注释掉定义,程序将无缝地使用矢量版本。在第一种情况下,我期待编译器抱怨!

#include <iostream>
#include <vector>
using namespace std;

void print(const vector<int>& v1){
        cout << "vector \n";
}
void print(const initializer_list<int>& il) {
         cout << "init list \n";
}

int main() {
        print({1,2,3,4,5});
        return 0;
}

2 个答案:

答案 0 :(得分:1)

这就是overload resolution在C ++中的工作方式。 print的两个版本都可用于重载解析。

  • print(const vector<int>& v1)是一种可行的重载解析函数,因为调用者中的输入初始化列表{1,2,3,4,5}可以隐式转换为std::vector<int>
  • print(const initializer_list<int>& il)是一个可行的重载解析函数,因为调用者中的输入类型完全匹配。

当两个重载进入播放时{I}被选为最佳可行函数,因为它是完美匹配,完美匹配在重载决策中的优先级高于隐式转换。

答案 1 :(得分:0)

重载解析的工作原理是将参数转换为参数类型所需的操作为转换序列,然后根据某些规则对转换序列进行排序。

由于我们正在初始化引用,[over.ics.ref] / 2适用:

  

当引用类型的参数没有直接绑定到参数表达式时,转换序列是根据13.3.3.1将参数表达式转换为引用的基础类型所需的转换序列。从概念上讲,此转换序列对应于使用参数表达式复制初始化基础类型的临时值。顶级cv资格的任何差异都归入初始化本身,并不构成转换。

因此,这允许我们使用相同的转换序列规则,就好像代码是:

void o_print(initializer_list<int> ol);
void o_print(vector<int> o1);

即。使用非const对象作为参数而不是const引用。

现在:

  • 根据[over.ics.list] / 2,将int的支持列表转换为std::initializer_list<int>身份转换。 (如果列表成员需要升级或转换为int,则不会。)

  • 根据[over.ics.list] / 4,将支撑列表转换为非聚合类(此处为std::vector<int>)通过重载决策选择std::vector的构造函数,并且此序列定义为用户定义的转换序列

最后,我们现在准备应用排名规则。身份转换的排名高于用户定义的转换序列,因此initializer_list<int>版本获胜。

NB。所有引用都是针对C ++ 14。