c++ - std::set 使用初始化列表插入

标签 c++ c++11 overload-resolution

我有这个简单的代码:

struct Base
{
    Base(int xx, int yy) : x(xx), y(yy){}
    bool operator<(const Base& b) const {return (x < b.x) || (x==b.x && y < b.y);}

    int x;
    int y;
};

struct D1 : Base
{
    D1(int x, int y) : Base(x, y){}
};

struct D2 : Base
{
    D2(int x = 0, int y = 0) : Base(x, y){}
};

void test()
{
    std::set<D1> s1;
    std::set<D2> s2;

    s1.insert({1, 2});
    s2.insert({1, 2});

    std::cout<<"s1 size:"<<s1.size()<<std::endl<<"Content:"<<std::endl;
    for(auto& v : s1)
    {
        std::cout<<v.x<<" "<<v.y<<std::endl;
    }

    std::cout<<std::endl<<"s2 size:"<<s2.size()<<std::endl<<"Content:"<<std::endl;
    for(auto& v : s2)
    {
        std::cout<<v.x<<" "<<v.y<<std::endl;
    }
}

输出:

s1 size:1
Content: 
1 2

s2 size:2
Content:
1 0
2 0

为什么插入带有默认参数的对象时行为不同?这是错误还是预期的行为?

PS:您可以在此处查看代码:https://ideone.com/UPArOi

最佳答案

这里的经验法则是 initializer_list<X>与其他重载相比,重载是强烈推荐的。

首先来自[over.ics.list]

if the parameter type is std::initializer_list<X> and all the elements of the initializer list can be implicitly converted to X, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to X, or if the initializer list has no elements, the identity conversion. This conversion can be a user-defined conversion even in the context of a call to an initializer-list constructor.

并且,来自 [over.ics.rank]:

List-initialization sequence L1 is a better conversion sequence than list-initialization sequence L2 if
— L1 converts to std::initializer_list<X> for some X and L2 does not [...]

我们有两个相关的重载 std::set::insert :

std::pair<iterator,bool> insert( value_type&& value );
void insert( std::initializer_list<value_type> ilist );

第一次调用:

s1.insert({1, 2});

考虑参数类型为 std::initializer_list<D1> 的重载.都不是1也不2可以隐式转换为 D1 ,所以过载是不可行的。现在考虑 D1&&重载。因为我们可以构造一个 D1使用该初始化列表,即选择的重载,我们最终得到一个元素:D1{1, 2} .

但是,在这种情况下:

s2.insert({1, 2});

两者都是 12 可以隐式转换为D2 , 感谢 D2 中的默认参数的构造函数。所以 initializer_list<D2>过载是可行的。 D2&&过载也是可行的,但是 initializer_list conversion sequence 是一个更好的转换序列,所以它是首选。这给了我们两个元素,D2{1}D2{2} .

关于c++ - std::set 使用初始化列表插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32586871/

相关文章:

c++ - 跟踪成员变量值变化

c++ - 我可以将 libcurls CURLOPT_WRITEFUNCTION 与 C++11 lambda 表达式一起使用吗?

Swift:为函数类型专门化泛型类的方法

c# - 方法重载决议系统如何决定在传递空值时调用哪个方法?

c++ - 动态数组成员变量

c++ - 类作为参数错误

c++ - 构造函数的初始化列表

c++ - 重载解析、模板和继承

c++ - 在 C++ 中测量 popcount 函数的时间

php - 如何在 php 扩展中返回 $this?