英文:
Is it possible to use the brace initialiser list syntax for private members?
问题
以下是您要翻译的内容:
以下代码可编译:
#include <vector>
struct Foo
{
int a;
int b;
};
int main()
{
std::vector<Foo> foos;
foos.emplace_back(Foo{1, 2});
}
然而,如果我将 struct
替换为 class
,它会失败。除了这个更改(我想保持成员私有),是否有什么我可以做的,以便我可以使用 Foo{1, 2}
的表示法?我很想避免自己编写一个 Foo
构造函数。
我正在使用 C++17,当然也对一般性的 C++ 答案感兴趣。
注释:
- 编译错误(MSVC)如下:
c:\...: error C2440: 'initializing': 无法从 'initializer list' 转换为 'Foo'
c:\...: note: 源类型无法接受,或构造函数重载解析模糊
c:\...: error C2672: 'std::vector<Foo,std::allocator<_Ty>>::emplace_back': 找不到匹配的重载函数
with
[
_Ty=Foo
]
英文:
The following code compiles
#include <vector>
struct Foo
{
int a;
int b;
};
int main()
{
std::vector<Foo> foos;
foos.emplace_back(Foo{1, 2});
}
However, it fails if I replace struct
with class
<sup>1</sup>. Aside from doing that (I would like to keep the members private), is there something I can do to enable me to use the Foo{1, 2}
notation? I'm keen to avoid writing a constructor for Foo
myself.
I'm using C++17 although of course will be interested in general C++ answers.
<hr>
<sup>1</sup> Compile error (MSVC) is
1>c:\...: error C2440: 'initializing': cannot convert from 'initializer list' to 'Foo'
1>c:\...: note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>c:\...: error C2672: 'std::vector<Foo,std::allocator<_Ty>>::emplace_back': no matching overloaded function found
1> with
1> [
1> _Ty=Foo
1> ]
答案1
得分: 2
你正在使用的功能称为聚合初始化。根据C++17标准中对聚合的定义[dcl.init.aggr/1.2]:
> 聚合是一个数组或一个满足以下条件的类
(1.1) 没有用户提供的、显式的或继承的构造函数
(1.2) 没有私有或受保护的非静态数据成员
...
因此,要实现你的要求,没有实现构造函数是不可能的。背后的原因很简单 - 如果类/结构体定义了某些成员为私有,就不应该以任何方式从外部访问它们。否则,这就违反了封装的概念。
请注意,花括号本身不一定表示聚合初始化。例如,Foo{a, b}
是调用构造函数的有效语法:
class Foo
{
int a;
int b;
public:
Foo(int a_, int b_) : a{a_}, b{b_} {}
};
Foo f{1, 2}; // 在这里调用构造函数
英文:
The feature you are using here is called aggregate initialization. By definition of aggregate from the C++17 standard [dcl.init.aggr/1.2]:
> An aggregate is an array or a class with
(1.1) no user-provided, explicit, or inherited constructors
(1.2) no private or protected non-static data members
...
Thus, it's just impossible to do what you are asking for without implementing a constructor. The reasoning behind this is simple - if class/struct defines something to be private, it shouldn't be accessible from outside in any way. Otherwise, it contradicts the concept of encapsulation.
Please note that the curly braces themselves don't necessarily mean aggregate initialization. Foo{a, b}
is a valid syntax for calling a constructor, for example:
class Foo
{
int a;
int b;
public:
Foo(int a_, int b_) : a{a_}, b{b_} {}
};
Foo f{1, 2}; // Calls constructor here
答案2
得分: 1
private
意味着它是私有的。这是一个实现细节。用户不必关心它。您可以更改或删除私有成员,类的用户不会注意到,只要不触及公共接口,他们的代码将继续编译而不会出错。
编写一个构造函数:
struct Foo
{
Foo(int a, int b) : a(a), b(b) {}
private:
int a;
int b;
};
为了说明我的观点,考虑以后您将类更改为:
struct Foo
{
Foo(int a, int b) : ab(a + b) {}
private:
int ab;
};
不同范围的输入导致溢出和不同的 sizeof
,用户不会注意到差异。这是好的,因为只有私有部分被修改。
英文:
private
means its private. Its an implementation detail. A user does not have to care about it. You can change or remove private members and a user of the class will not notice, their code will continue to compile without errors as long as the public interface is not touched.
Write a constructor:
struct Foo
{
Foo(int a,int b) : a(a),b(b) {}
private:
int a;
int b;
};
To illustrate my point, consider later you change the class to
struct Foo
{
Foo(int a,int b) : ab(a+b) {}
private:
int ab;
};
Different ranges of input leading to overflow and different sizeof
aside, a user will not notice the difference. And thats good, because only the private part was modified.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论