设计具有变体字段的文本类型类,其中可以存储一个或三个对象
Designing a literal-type class with a variant field inside in which one or three objects may be stored
我正在尝试设计一个类 - 为了讨论起见,我们称之为A
- 它将满足一组特定的要求:
A
必须是文本类型,以允许编译器在编译时通过constexpr
构造函数初始化其全局实例(在源代码中创建许多这种类型的全局const
对象)。这样做的原因是A
对整数使用了简单的编译时加密(主要是 XOR)。稍后在运行时访问相应的int
时完成解密。- 它的中央私有字段是一个简单的整数。但是,该类有两个构造函数:
A::A(int x)
和A::A(int x, int y, int z)
.如果调用第一个版本,则稍后在运行时,每当进行需要使用它的方法调用时,类将在内部使用该单个x
。相反,如果使用具有三个参数的第二个版本,则在运行时将决定在调用需要x
、y
和z
中的哪一个。 A
必须是单个类型;第一个构造函数的一个类型,第二个构造函数的另一个类型不令人满意(A
经常作为参数传递给函数,所以如果没有这个约束,我需要复制或模板化所有这些函数)。- 所有
A
对象中的绝大多数都是全局常量,赋值很少发生,如果是这样,它肯定不会在具有三个int
的对象和具有一个int
的对象之间,反之亦然。
总结一下:A
将被实例化为全局const
对象。如果我用单个int
初始化一个对象,该单个int
应该存储在其中(仅此而已)。如果我用三个int
初始化它,那么这三个int
应该存储在里面。无需担心从三int
对象到一int
对象的赋值,反之亦然,因为它们都是常量。
到目前为止,我考虑的解决方案如下:
-
A
做一个模板;模板参数就是我所说的StorageType
。该存储将通过公开该中心int
资源的访问器来抽象对该资源的访问。然后,选择要使用的int
字段的问题将从A
移动到此帮助程序存储类型。这个想法大致由以下代码说明:template<typename StorageType> class A { private: StorageType storage; public: constexpr A(int x, int y, int z) : storage(x, y, z) { } constexpr A(int x) : storage(x) { } void doSomething() { auto theRightInt = storage.getInt(); // ... } };
问题:违反约束 3。
-
和以前一样,但不是在
StorageType
上模板化A
,有一个描述StorageType
的通用接口,并在A
内部存储一个unique_ptr
。问题:违反约束 1。
-
将整数存储为联合:
union { struct { int x; int y; int z; } intPack; int singleInt; };
在此变体中,每个
A
对象(包括仅使用单个int
的对象)都有三个可能int
的空间。另一种选择是使用boost::variant
而不是过时的union
.问题:这是浪费 - 见第4点。如果使用
boost::variant
,则违反约束 1,因为与 C++17 中的std::variant
不同,boost::variant
不是文本类型。 -
与其试图在
A
内部表示中心整数字段的"方差",不如在外部进行:让类始终存储单个int
,并创建一个辅助类 - 我们称之为VariantA
- 其中包含三个版本的A
,每个版本都使用第2点提到的构造函数中x
,y
和z
的内容进行初始化。VariantA
将有一个访问器函数,该函数在运行时决定返回哪个A
对象。问题:使用起来很乏味,因为每次都必须调用访问器:
VariantA a1(0, 1, 2); VariantA a2(10, 20, 30); auto a3 = a1.get() + a2.get(); someFunctionThatTakesAnA(a1.get()); // etc
问题:对于这个问题,是否有我错过的优雅解决方案,或者我是否必须选择我上面考虑(并拒绝)的解决方案之一? 我的平台是VC++,所以使用C++11/4是可以的,除了一些更深奥的部分,但C++17草案的功能尚不可用。
似乎您可以使用的最好的东西是有条件大小的整数范围:
class A {
std::array<int, 3> data;
bool one;
public:
constexpr A(int x): data{{x, 0, 0}}, one(true) { }
constexpr A(int x, int y, int z): data{{x, y, z}}, one(false) { }
constexpr size_t size() const { return one ? 1 : 3; }
constexpr const int* begin() const { return data.data(); }
constexpr const int* end() const { return data.data() + size(); }
};
我不完全确定你选择哪个元素的逻辑是什么,但是如果你有一个 1 大小的范围,你会得到那个元素,如果你有一个 3 大小的范围,那么你做你需要做的任何事情。
不管具体细节如何,重点是你想要一个有 3 个int
s 和一个bool
的类型。你需要存储 3int
秒,你希望它是文字的,并且你想让它知道它是存储 3 还是 1int
。这几乎说明了类型。剩下的唯一事情是确定您希望数据访问的外观,这没有指定。
一个有 2 个成员的类/结构?
指向int
的指针和bool
(布尔值表示指针指向一个还是三个值)?
#include <iostream>
struct foo
{
bool single;
int const * p;
constexpr foo ( int const & x ) : single{true}, p{&x}
{}
constexpr foo ( int const * y ) : single{false}, p{y}
{}
};
constexpr int x{2};
constexpr int y[]{3, 5, 7};
int main ()
{
constexpr foo f1{x};
constexpr foo f3{y};
}
- C++ 在堆栈中包含多态属性的类对象存储
- 将对象存储为其基本虚拟类
- 将大型对象存储在无序映射中是否效率低下
- C++:将未知类型的对象存储为成员变量的类
- 按unique_pointer将传递的对象存储在地图中
- 如何将 c++ 类对象存储为数组?
- 将对象存储在 std::map 中
- 是否存在对象存储在其生存期内可能会更改的情况?
- 将不同类型的对象存储在容器中
- 将自定义可绘制对象存储在数组中会导致绘制时出现分割错误
- 我将如何在C++中文件处理对象(存储/导入)
- 将对象存储在C 中的2维Sprite矩阵中
- 将抽象派生类对象存储在基类向量中
- 将任意函数对象存储到类成员容器中,而无需知道其声明签名
- 如何使用向量将类对象存储在超载操作员中
- 适当的方法将对象存储在Std矢量中
- 将向量对象存储在共享指针投掷错误中
- 将多态对象存储在unordered_set中
- 为什么我可以将对象存储在大小不同的数组中
- 返回对象存储在哪里