如何根据参数在复制构造函数和默认构造函数之间切换?
How to switch between copy-constructor and default constructor depending on argument?
我有以下代码:
struct S
{
S(): a(42) {}
int a;
};
class P
{
public:
P(S const *s): m_s(s ? *s : /*init m_s by default ctor - how to achieve it?*/)
private:
S m_s;
};
我希望 m_s
由复制构造函数或默认构造函数初始化,具体取决于指针 s
:
P p1(nullptr); // expect default ctor: p1.m_s.a = 42
S s;
s.a = 84;
P p2(&s); // expect copy ctor: p2.m_s.a = 84
我怎样才能以最优雅的方式做到这一点?
仅适用于空指针常量的部分解决方案是添加重载:
P(std::nullptr_t) : m_s() {}
P(const S * s) : m_s(AssertNotNull(s)) {}
这里我用了:
template <typename T> T * AssertNotNull(T * p) {
if (!p) std::abort();
return p;
}
如果需要动态切换,可以使用辅助函数:
struct P {
static const S & maybe(const S * s) {
static S x;
return s ? *s : x;
}
P(const S * s) : m_s(maybe(s)) {}
S m_s;
}
这实际上并没有在复制构造函数和默认构造函数之间切换(因为您不能动态地这样做),但是如果指针为空,它会通过从默认构造的实例进行复制来伪造效果。
你可以这样写:
class P {
public:
P(S const *s): m_s(s ? *s : S()){}
private:
S m_s;
};
您可能会发现将条件提取到单独的辅助函数中更优雅:
S createS(S const *s) {
return s ? *s : S();
}
这可能看起来会在 nullptr
参数的情况下执行不必要的复制,但实际上编译器将执行 RVO 并优化复制。
我有以下代码:
struct S
{
S(): a(42) {}
int a;
};
class P
{
public:
P(S const *s): m_s(s ? *s : /*init m_s by default ctor - how to achieve it?*/)
private:
S m_s;
};
我希望 m_s
由复制构造函数或默认构造函数初始化,具体取决于指针 s
:
P p1(nullptr); // expect default ctor: p1.m_s.a = 42
S s;
s.a = 84;
P p2(&s); // expect copy ctor: p2.m_s.a = 84
我怎样才能以最优雅的方式做到这一点?
仅适用于空指针常量的部分解决方案是添加重载:
P(std::nullptr_t) : m_s() {}
P(const S * s) : m_s(AssertNotNull(s)) {}
这里我用了:
template <typename T> T * AssertNotNull(T * p) {
if (!p) std::abort();
return p;
}
如果需要动态切换,可以使用辅助函数:
struct P {
static const S & maybe(const S * s) {
static S x;
return s ? *s : x;
}
P(const S * s) : m_s(maybe(s)) {}
S m_s;
}
这实际上并没有在复制构造函数和默认构造函数之间切换(因为您不能动态地这样做),但是如果指针为空,它会通过从默认构造的实例进行复制来伪造效果。
你可以这样写:
class P {
public:
P(S const *s): m_s(s ? *s : S()){}
private:
S m_s;
};
您可能会发现将条件提取到单独的辅助函数中更优雅:
S createS(S const *s) {
return s ? *s : S();
}
这可能看起来会在 nullptr
参数的情况下执行不必要的复制,但实际上编译器将执行 RVO 并优化复制。