当存在其他构造函数时,如何强制创建默认序列构造函数?
How to force creation of default sequence constructor when other constructors are present?
从 C++11 开始,我们有了这个很棒的特性,它允许我们避免为所有小 类 像这样的东西显式创建构造函数:
class A
{
public:
A() = default;
A(int x, int y) : x(x), y(y) {} // bloat
int x = 0, y = 0;
};
..
A a(1,2);
所以我们现在可以这样写:
class A
{
public:
int x = 0, y = 0;
};
..
A a{1,2}; // using the sequence constructor created by the compiler, great
问题出现了,当我还有其他我想使用的构造函数时,例如:
class A
{
public:
A() = default;
A(Deserialiser& input) : a(input.load<int>()), b(input.load<int>()) {}
int x = 0, y = 0;
};
...
A a{1, 2}; // It doesn't work now, as there is another constructor explicitly specified
问题是,我如何强制编译器创建默认序列构造函数?
与第二个示例的不同之处在于您正在做 aggregate initialization。
对于第一个和第三个示例,聚合初始化不再可能(因为 class 具有用户定义的构造函数)。
在第一个示例中,调用了双参数构造函数。对于第三个例子,找不到合适的构造函数,你会得到一个错误。
注意:在 C++11 中,第二个示例也无法进行聚合初始化,因为 C++11 不允许内联初始化非静态成员。该限制在 C++14 中被移除。 (有关详细信息,请参阅上面的链接参考。)
如果您命名一个构造函数,您将删除所有其他自动生成的名称。
通过命名 A(Deserialiser&)
,您丢失了自动生成的 A(int, int)
表达构造函数的方式是:
class A
{
public:
A() : A(0, 0) {} // <- set default values here
A(int x, int y) : x(x), y(y) {}
A(Deserialiser& input) : x(input.load<int>()), y(input.load<int>()) {}
int x, y;
};
保留聚合初始化的一种方法是将序列化与对象本身分离。
template<class Type> struct type_tag {};
class A
{
public:
A() = default;
int x = 0, y = 0;
};
auto deserialise(Deserialiser& input, type_tag<A>)
{
return A { input.load<int>(), input.load<int>() };
}
只要您没有为 class 提供任何构造函数,编译器就会自动生成默认构造函数。但是一旦你提供了至少一个构造函数,那么即使没有更多的默认构造函数,编译器也不会提供任何构造函数。
从 C++11 开始,我们有了这个很棒的特性,它允许我们避免为所有小 类 像这样的东西显式创建构造函数:
class A
{
public:
A() = default;
A(int x, int y) : x(x), y(y) {} // bloat
int x = 0, y = 0;
};
..
A a(1,2);
所以我们现在可以这样写:
class A
{
public:
int x = 0, y = 0;
};
..
A a{1,2}; // using the sequence constructor created by the compiler, great
问题出现了,当我还有其他我想使用的构造函数时,例如:
class A
{
public:
A() = default;
A(Deserialiser& input) : a(input.load<int>()), b(input.load<int>()) {}
int x = 0, y = 0;
};
...
A a{1, 2}; // It doesn't work now, as there is another constructor explicitly specified
问题是,我如何强制编译器创建默认序列构造函数?
与第二个示例的不同之处在于您正在做 aggregate initialization。
对于第一个和第三个示例,聚合初始化不再可能(因为 class 具有用户定义的构造函数)。
在第一个示例中,调用了双参数构造函数。对于第三个例子,找不到合适的构造函数,你会得到一个错误。
注意:在 C++11 中,第二个示例也无法进行聚合初始化,因为 C++11 不允许内联初始化非静态成员。该限制在 C++14 中被移除。 (有关详细信息,请参阅上面的链接参考。)
如果您命名一个构造函数,您将删除所有其他自动生成的名称。
通过命名 A(Deserialiser&)
,您丢失了自动生成的 A(int, int)
表达构造函数的方式是:
class A
{
public:
A() : A(0, 0) {} // <- set default values here
A(int x, int y) : x(x), y(y) {}
A(Deserialiser& input) : x(input.load<int>()), y(input.load<int>()) {}
int x, y;
};
保留聚合初始化的一种方法是将序列化与对象本身分离。
template<class Type> struct type_tag {};
class A
{
public:
A() = default;
int x = 0, y = 0;
};
auto deserialise(Deserialiser& input, type_tag<A>)
{
return A { input.load<int>(), input.load<int>() };
}
只要您没有为 class 提供任何构造函数,编译器就会自动生成默认构造函数。但是一旦你提供了至少一个构造函数,那么即使没有更多的默认构造函数,编译器也不会提供任何构造函数。