类型双关、联合和 std::stack

-1 c++ stack struct unions

假设我想将不同类型的数据推送到标准库堆栈中。为了简单起见,我只采用两种类型:

  • 整数
  • foo(类)

为此,我需要以下数据结构:

//generic class
class foo {
  private:
    float x_;
  public:
    foo(float x) : x_(x){};
};
 
//simple enum
enum element_type {
  footype,
  number
};

struct stack_element {
  element_type type_;
  union {
    foo* obj;
    int num;
  } data;
};
Run Code Online (Sandbox Code Playgroud)

然后我需要在结构体中创建一个构造函数以实现类型双关:

//actually this should be if/else statement in this case but on the code problem I have more types
stack_element(element_type type, foo* obj){
  switch(type){
    case footype: 
      this->type_ = type;
      this->data.obj = obj;
    break;
    case number:
      this->type_ = type;
      // Here comes the type punning
      this->data.num = *(int*)&obj;
    break;
    default: throw("Unknown type");
    break;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后 main.cc 看起来像这样:

#include <stack>
#include <iostream>

int main(){

  foo myobj (3.24);
  int a = 2;

  std::stack < stack_element > mystack;

  mystack.push (stack_element (element_type::footype, &myobj));
  mystack.push (stack_element (element_type::number, (foo *) a));

  do {
    if(mystack.top().type_ == number){
      std::cout << (int)mystack.top().data.num << std::endl;
      mystack.pop();
    }
    else{
      mystack.top().data.obj->print_foo();
      mystack.pop();
    }
  }while(!mystack.empty());
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这将编译一个警告,这显然是有意义的:

main.cpp:73:62:警告:从不同大小的整数转换为指针[-Wint-to-pointer-cast] 73 | mystack.push (stack_element (element_type::number, (foo *) a));

现在基础已经确定,我有几个问题:

  • 是否有任何其他解决方法可以更有效地实现相同的目标。
  • 我读到这种方式并没有被真正接受,现在我们自 c++17 以来有了 std::variant 但正如它所说:

不允许变体保存引用、数组或 void 类型。(除非您使用引用包装器。)

我应该使用 std::variant 而不是这个联合/结构吗?

  • 我想这不是一个真正安全的代码,对吗?

eer*_*ika 5

我应该使用 std::variant 而不是这个联合/结构吗?

是的,您应该使用std::variant而不是struct stack_element.

我想这不是一个真正安全的代码,对吗?

不,您的代码并不真正安全。