现代 C++ 中调用 constructor 是习惯使用 (...args) 还是 {..args}
Criado em: 5 de setembro de 2026
Respondido usando GPT-5.6 Thinking por Chat01
Criado em: 5 de setembro de 2026
Respondido usando GPT-5.6 Thinking por Chat01
现代 C++ 中调用 constructor 是习惯使用 (...args) 还是 {..args}
在现代 C++ 里,两种都常见,但我更建议把 () 当作“调用普通 constructor”的默认写法,把 {} 留给你确实想要 list-initialization 语义的时候。
原因是 {} 不只是换一种括号,它会改变重载决议:如果类有 std::initializer_list constructor,{} 会优先考虑它。(Cppreference)
最经典的例子:
cppstd::vector<int> a(10, 20); // 10 个元素,每个都是 20 std::vector<int> b{10, 20}; // 2 个元素:10, 20
所以对于:
cppFoo x(arg1, arg2);
我通常会写成这样。它清晰表达:
“我要用
(arg1, arg2)这组参数做普通 constructor overload resolution。”
而:
cppFoo x{arg1, arg2};
表达的是 list-initialization。它有两个重要特性:
cppint a(3.14); // OK,a == 3 int b{3.14}; // compile error
这是 {} 很大的安全优势。(Cppreference)
initializer_list constructor 有特殊优先级:cppclass Foo { public: Foo(int, int); Foo(std::initializer_list<int>); }; Foo a(1, 2); // Foo(int, int) Foo b{1, 2}; // Foo(initializer_list<int>)
因此它们并不是单纯的 stylistic alternatives。
cpp// 普通 constructor Foo foo(a, b); // aggregate / struct 数据初始化 Point p{10, 20}; // container 明确列出元素 std::vector<int> xs{1, 2, 3}; // value initialization / zero initialization int n{}; Foo foo{}; // 避免 narrowing 时 SomeType x{value};
尤其是泛型代码,我会明显偏向:
cppreturn T(std::forward<Args>(args)...);
而不是:
cppreturn T{std::forward<Args>(args)...};
因为后者可能意外触发 initializer_list overload,导致泛型代码的语义发生变化。
值得一提的是,C++ Core Guidelines 的 ES.23 确实给出了更强的意见:“Prefer the {}-initializer syntax”,理由包括统一语法、禁止 narrowing,以及避免某些 () 的语法歧义。(ISO C++) 所以你也会看到不少现代 C++ 项目坚持“几乎全部 {}”。
不过工程实践里,initializer_list 的优先级问题使得很多开发者不会无脑遵循“everything braces”。
所以如果要压缩成一个规则:
普通构造用
();表达“一组值/成员/元素”用{};需要防 narrowing 时也优先{}。
比如看到:
cppWidget w(10, 20); Point p{10, 20}; std::vector<int> v{10, 20};
我会认为这是非常自然、现代而且语义明确的 C++ 风格。
另外,“constructor 本身”的声明当然仍然是 Foo(int x);这里讨论的是对象初始化时选择 () 还是 {}。cppreference 也明确区分 direct-initialization 和 list-initialization。(Cppreference)