c++ - 为什么存在 C++11 std::initializer_list 构造函数重载规则?

标签 c++ c++11 initializer-list

我似乎无法想到也找不到以下代码的理由:

std::vector<int> a{1,2} // calls (7)
std::vector<int> a(1,2) // calls (2)

// constructors from http://en.cppreference.com/w/cpp/container/vector/vector
vector( std::initializer_list<T> init, 
        const Allocator& alloc = Allocator() ); // (7)

explicit vector( size_type count, 
                 const T& value = T(),
                 const Allocator& alloc = Allocator()); // (2)

根据您使用的构造方法调用不同的函数({}()),这对我来说似乎非常反常。为什么是std::initializer_list比其他完全匹配给定参数的函数更受欢迎? 我知道构造函数2 above 在 C++11 中被弃用,大概是因为这个变化,但我仍然无法解释为什么是这种情况。对于这种行为,我能看到的唯一好处是您可以使用特定值初始化容器,并且只需要一对大括号; std::vector<int> a{1,2}对比std::vector<int> a{{1,2}} .但是,至少对我来说,这肯定不会超过由此带来的歧义和重载解决方案的变化。根据 Effective Modern C++ 中的 Scott Meyers,std::make_uniquestd::make_shared需要明确说明使用哪种形式作为其接口(interface)的一部分进行构造(由于重载决议)。这对我来说似乎很荒谬。

我承认我一定遗漏了什么,但我不确定是什么。请注意,我刚刚使用了 std::vector举个例子,我问的是一般的功能。

最佳答案

这对于 C++11 来说很有趣:原因是花括号参数没有类型。但这有一个异常(exception),我不清楚它存在的原因:“auto”变量是唯一允许将大括号参数隐式视为初始化列表的变量。但是如果你有一个自动函数类型,它不允许返回这个初始化列表。

现在,你是对的:初始化列表的一个好处是你可以用特定的值初始化一个容器。这是一个值得改变的巨大好处!

在初始化器列表之前,制作一个模板允许您使用不同的值初始化容器内的每个类需要严格的解决方案,比如接收一个带有每个值的 std::vector,或者构建一个“空”模板类,然后打洞之后的每个值。

另一件事是,初始化列表允许您以比使用这个可怕的 <cstdarg> 更安全的方式为 C++ 创建可变参数函数。从 C 导入。(尽管可变参数模板在这方面做得更好)

想尝试一下组合吗?

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;


vector<int> func (const vector<int> &a) { //works
//auto func (const vector<int> &a) -> vector<int> { //works
//auto func (const vector<int> &a) { //don't even compile, "returns a initializer list" error
    for (int i: a) {
        cout << "My " << i << endl;
    }

    return {20 , 30};
}

int main()
{
    //play with anonymous functions
    auto y = [ ](vector<int> e) { return e; }; //works
    vector<int> x = y({20, 30});
    //auto y = [ ](){ return {20, 30}; }; //don't even compile, "returns a initializer list" error
    //vector<int> x = y();

    //play with initialization
    //vector<int> x = {2,2,20,30}; //works
    //vector<int> x{2,2,20,30}; //works
    //auto x = vector<int>{2,2,20,30}; //works
    //Bellow, a common mistake of people initializing a int to a auto, like auto x = { 1 }
    //auto x = {2,2,20,30}; //wrong, but compiles, its a initializer list
    //auto x{2,2,20,30}; //wrong, but compiles, its a initializer list

    //Play with return types
    //vector<int> x = func(vector<int>(2,2));  //works only with vector<int> and auto with trailing type
    //vector<int> x(func(vector<int>(2,2))); //works only with vector<int> and auto with trailing type
    //vector<int> x{func(vector<int>(2,2))}; //works only with vector<int> and auto with trailing type
    //auto x = func(vector<int>(2,2));  //works only with vector<int> and auto with trailing type
    //auto x(func(vector<int>(2,2))); //works only with vector<int> and auto with trailing type

    cout << typeid(x).name() << endl;
    for (int i: x) {
        cout << "My " << i << endl;
    }

    return 0;
}

关于c++ - 为什么存在 C++11 std::initializer_list 构造函数重载规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28270217/

相关文章:

c++ - 全局设置 stringstream 的精度

c++ - 线程不起作用并出现错误:启用多线程以使用 std::thread:不允许操作

initialization - 如何使用统一初始值设定项 "reduce typing to create C++ types"?

c++ - 使用多维 std::initializer_list

c++ - 将 initializer_list 插入 vector<string> 时 VS2013 SP5 崩溃

c++ - 程序无法使用 g++ 编译

c++ - 头文件中非静态成员函数的使用无效

c++ - 如果在 c++ 之前未定义,则定义函数/方法

c++ - .get() 和 -> 与智能指针之间有区别吗?

c++ - 初始化 POD 结构的基类