我有一些类,有一些成员:
#include <variant>
class A {
public:
A() {};
private:
B b;
std::variant<B, C> var;
};
class B {
public:
B(C c) : c(c) {};
private:
C c;
};
class C {
public:
C(int val) val(val) {};
private:
int val;
};
现在,由于两个原因,这当然不会编译:类B
和variant
都没有默认构造函数。但我还没有B
或var的任何值,它们将在A
的方法中初始化。
我想到了以下几点:
- 定义
B
的默认构造函数。但这样我会有一个不必要的构造函数和我也必须对C
做同样的操作。由于我可能有多个子类,这将导致快速生成不必要的构造函数。此外,我不能为此而不诸如CCD_ 7的自定义类 - 使用伪值初始化变量。虽然在实践中,这可能会起作用,因为无论如何我都会很快覆盖值,但这不是很干净,可能会导致一些丑陋的错误
- 使用指针。这可能是最现实的一个,也是我觉得最合理的一个。但出于某种原因,我真的想避免这里的指针。此外,当我尝试使用指针时,由于某种原因,B的成员在返回成员后发生了奇怪的变化。此外,当尝试使用变体(如
var = &C(0);
(时,我被告知
类型为";C*";不能分配给类型可变的实体
来自Java,有没有任何方法可以(不使用指针(将值初始化为类似null
的值?我知道null
是C++不存在的,但我正在寻找具有相同效果的东西/一些解决缺少默认构造函数的方法。还是这是我的类中的一个设计缺陷,应该完全不同地解决?
您可以在变体中使用std::monostate
,直到您选择了要存储的类型。
std::monostate
:
在
std::variant
中用作性能良好的空替换项的单元类型。特别是,非默认可构造类型的变体可能会将std::monostate
列为其第一个备选方案:这使得变体本身具有默认可构造性。
大纲:
class A {
public:
A() = default;
A(const B& b) : var(b) {}
A(const C& c) : var(c) {}
A& operator=(const B& b) {
var = b;
return *this;
}
A& operator=(const C& c) {
var = c;
return *this;
}
private:
std::variant<std::monostate, B, C> var;
};
如果您想向A
添加更多类型,而不必为所有类型显式添加构造函数和赋值运算符,那么这是一个更通用的版本:
#include <type_traits>
#include <utility>
#include <variant>
template<class... Ts>
class A_impl {
public:
A_impl() = default;
template<class T>
requires std::disjunction_v<std::is_same<std::remove_cvref_t<T>, Ts>...>
A_impl(T&& val) : var(std::forward<T>(val)) {}
template<class T>
requires std::disjunction_v<std::is_same<std::remove_cvref_t<T>, Ts>...>
A_impl& operator=(T&& val) {
var = std::forward<T>(val);
return *this;
}
private:
std::variant<std::monostate, Ts...> var;
};
using A = A_impl<B, C>;