C++“选择”联合

r8uurelv  于 2023-01-06  发布在  其他
关注(0)|答案(4)|浏览(160)

不确定是否有一个术语来描述这个,“选择”似乎起作用了。我在C中工作,我需要创建一堆联合体,其中联合体表示联合体成员之一的选择。当前的“选择”被跟踪,并且总是可用的。我目前正在手动编写这些“联合体”,但我想知道是否有什么巧妙的技巧可以(半)自动地完成这类事情。
在我第一次尝试实现这个的时候,我遇到了union的限制,即没有赋值运算符重载、非平凡构造函数或复制构造函数,但是我意识到,因为我实际上是在跟踪当前的“选择”,所以几乎在每种情况下都有非常明确的行为。
这是我现在正在做的,(只有两个选择,可能是10或15),这是相当可观的代码量几乎所有的只是样板.此外,如果有人有任何意见,我下面的是不是甚至有效,这将是真棒,仍然拿起一些疯狂的C
...

struct MyChoice
{
    struct Choice1
    {
        int a;
        char* b;
    };

    struct Choice2
    {
        bool c;
        double d;
    };

    enum Choice
    {
        Choice_Choice1,
        Choice_Choice2
    } choice;

    char _value[max(sizeof(Choice1),sizeof(Choice2))]; // could be private
    Choice1& choice1()
    {
        if(choice == Choice_Choice2)
        {
            (*(Choice2*)_value)->~Choice2();
            (*(Choice1*)_value) = Choice1();
            choice = Choice_Choice1;
        }
        return *(Choice1*)_value;
    }
    Choice2& choice2()
    {
        if(choice == Choice_Choice1)
        {
             (*(Choice1*)_value)->~Choice1();
             (*(Choice2*)_value) = Choice2();
             choice = Choice_Choice2; 
        }
        return *(Choice2*)_value;
    }
    MyChoice()
    {
       _choice = Choice_Choice1;
       (*(Choice1)_value) = Choice1();
    }
    MyChoice(const MyChoice& other)
    {
       this->_choice = other.choice;
       if(this->_choice == Choice_Choice1)
          (*(Choice1*)_value) = other.choice1();
       else
          (*(Choice2*)_value) = other.choice2();
    }
    ~MyChoice()
    {
        if(_choice == Choice_Choice1)
            (*(Choice1)_value)->~Choice1();
        else
            (*(Choice2)_value)->~Choice2();
    }
};

谢谢你的帮助所以

xdyibdwo

xdyibdwo1#

试着看看boost::any和boost::variant。第一个允许你在boost::any变量中插入任何类型,跟踪它的类型。它更像是一个“运行时检查”类型。第二个强制你定义所有要插入的类型(即boost::variant〈Choice1,Choice2,...〉),但在编译时强制更多的类型检查。
这两种类型都用于存储不同类型的对象,例如,具有异构容器(例如,std::vector可以处理std::string或int)。

zlhcx6iw

zlhcx6iw2#

更一般地说,这是一个“区分联合”或tagged union。如前所述,boost::variant或boost::any都是此策略的实现。

mf98qq94

mf98qq943#

在C++ 17中,标准库中直接提供了std::variant类型。
下面是cppreference示例源代码的一小段摘录:

#include <variant>
#include <string>
#include <cassert>

using namespace std::literals;

int main()
{
    std::variant<int, float> v, w;
    v = 12; // v contains int
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // same effect as the previous line
    w = v; // same effect as the previous line

//  std::get<double>(v); // error: no double in [int, float]
//  std::get<3>(v);      // error: valid index values are 0 and 1
}
4urapxun

4urapxun4#

即使你像我一样,通常喜欢变体而不是继承(我是ML类型的人),继承也是C++的方式。
不要使用boost::variant<Apple, Pear, Banana>的对象,而是使用指向Fruit的对象的智能指针。继承的优点是开放的--你总是可以添加更多类型的Fruit。虚方法通常比开关或if语句干净得多。给予继承一个机会吧;你会喜欢的。

相关问题