6

不确定是否有一个术语,“选择”似乎有效。我在 C++ 中工作,我需要创建一堆工会,其中工会代表工会成员之一的选择。当前的“选择”被跟踪并且始终可用。我目前正在手动编码这些“联合”,但我想知道是否有任何巧妙的技巧可以(半)自动地完成这类事情。

在我第一次尝试实现这个时,我遇到了没有赋值运算符重载或非平凡构造函数或复制构造函数的联合限制,但我意识到因为我实际上是在跟踪当前的“选择”,所以有非常明确的行为几乎在所有情况下都能接受。

这就是我现在正在做的事情,(只有两个选择,可能最多 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();
    }
};

谢谢你的帮助

4

4 回答 4

15

尝试查看 boost::any 和 boost::variant。第一个使您可以在 boost::any 变量中插入任何类型,并跟踪其类型。它更像是一种“运行时检查”类型。第二个强制您定义要插入的所有类型(即 boost::variant < Choice1, Choice2, ... > ),但在编译时强制执行更多类型检查。

两者都用于存储不同类型的对象,例如具有异构包含(例如,std::vector 可以处理 std::string 或 int)。

于 2010-07-21T21:31:36.510 回答
6

更一般地说,这是一个“受歧视的工会”或标记的工会。如前所述, boost::variant 或 boost::any 都是该策略的实现。

于 2010-07-21T21:33:54.913 回答
4

在 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
}
于 2018-08-28T12:40:28.660 回答
3

即使你和我一样,通常更喜欢变体而不是继承(我是一个 ML 类型的人),继承是 C++ 的实现方式。

不要使用 的对象,而是使用boost::variant<Apple, Pear, Banana>指向 的对象的智能指针Fruit。继承具有开放性的优势——您总是可以添加更多类型的Fruit. 虚方法通常比开关或 if 语句更简洁。给继承一个机会;你会学会喜欢它。

于 2010-07-21T21:52:26.267 回答