【问题标题】:c++ : calling constructors via curly braces?c++:通过花括号调用构造函数?
【发布时间】:2020-05-28 10:46:49
【问题描述】:
class A 
{
    int value_;
    public:
    A(int value):value_(value){}
};

A get_a1(int value)
{
    return A(value);
}

A get_a2(int value)
{
    return {value};
}


int main()
{
    A a1 = get_a1(1);
    A a2 = get_a2(2);
}

get_a1()get_a2() 有什么区别?

return {value}; 怎么称呼? (我猜“通过花括号调用构造函数”不是引用 this 的正确方法)

【问题讨论】:

  • 我猜已经够接近了。这是一个“支撑初始化列表”,根据en.cppreference.com/w/cpp/language/initialization,我不精通标准语言,所以我会把完整的答案留给那些想要深入了解细节的人。
  • 我想到的两个区别是,如果你有 long value,它可能会在 get_a2 中警告你,或者如果 A 有一个 std::initializer_list 构造函数 get_a1get_a2 会使用不同的构造函数。
  • fwiw,return value; 也可以

标签: c++ constructor scope return


【解决方案1】:

在您的情况下,根本没有区别。但是如果你稍微修改一下你的代码,就会有明显的不同!

首先,你可以用不同的方式构造你的类型,这里都有描述:initilization

不同之处在于,如果您的类还提供了一个采用std::initializer_list 的构造函数。

请参阅以下修改/扩展的代码以显示差异:

class A 
{   
    public:
        A(int value):value_(value){ std::cout << "int" << std::endl;}
        A(const std::initializer_list<int>& ){ std::cout << "list" << std::endl;}
        void print()
        {   
            std::cout << value_ << std::endl;
        }   
    private:
        int value_;
};  

A get_a1(int value)
{   
    std::cout << "()" << std::endl;
    return A(value);
}   

A get_a2(int value)
{
    std::cout << "{}" << std::endl;
    return {value};
}


int main()
{   
    A a1 = get_a1(1);
    a1.print();
    A a2 = get_a2(2);
    a2.print();
}   

如果您运行该程序,您将看到使用{} 将使用std::initializer_list 调用构造函数,而使用() 将使用您的int 构造函数。

为什么在标准中有所描述:

§13.3.1.7 [over.match.list]/p1:

当非聚合类类型T 的对象被列表初始化时 (8.5.4),重载决议分两个阶段选择构造函数:

  • 最初,候选函数是类 T 的初始化列表构造函数 (8.5.4),参数列表包括 初始化器列表作为单个参数。
  • 如果没有找到可行的初始化列表构造函数,则再次执行重载决议,其中候选函数都是 T 类的构造函数和参数列表包括 初始化列表的元素。

如果初始化列表没有元素并且T 有一个默认值 构造函数,省略第一阶段。在复制列表初始化中, 如果选择了explicit 构造函数,则初始化为 格式不正确。

此外,初始化列表构造函数不允许缩小!

§8.5.4 列表初始化

(3.4) 否则,如果 T 是类类型,则考虑构造函数。适用的 枚举构造函数,并通过重载选择最好的构造函数 分辨率([over.match],[over.match.list])。如果缩小转换 (见下文)需要转换任何参数, 程序格式不正确。

【讨论】:

  • 如果我们扩展 OPs 的例子,可能会有更多的不同,例如如果列表中有多个元素,则从左到右排序评估;如果类是聚合,则行为不同。因为 OP 写了 {value} 而不是 A{value} 在 C++17 之前的额外移动构造中也存在潜在差异。而且我确定我忘记了一些东西。
  • @walnut 你是绝对正确的。我的想法是提供更多背景信息,无需过多修改即可观察到差异。如果只回答原始代码示例,也给出简单的答案:没有区别... :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-02
  • 2023-03-05
  • 2015-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多