【问题标题】:Any way of creating an array/vector which contains references to different types of variables?有什么方法可以创建包含对不同类型变量的引用的数组/向量?
【发布时间】:2017-02-27 19:20:51
【问题描述】:

我很长一段时间以来一直在努力尝试创建一个可以包含对多种类型变量的引用的数组/向量,请参见示例:

class Validate
{
private:
   some_array/vector[]; //0 would refer to x, 1 to y, and so on..
   uint8_t x;
   uint16_t y;
   int32_t z;
public:
   Validate();
   void doSomething(uint8_t &member);
   void doSomething(uint16_t &member);
   void doSomething(int32_t &member);
}

重点是我可以在“for循环”中轻松使用这个数组/向量,如下所示:

void Validate::doSomething(uint_8 &member)
{
   //Do whatever with the variable refered to.
}
Validate::Validate()
{
   for(int i = 0 ; i < 2 ; i++)
      doSomething(some_array/vector[i]);
}

也许有人对我有一个答案或更好的解决方案。

【问题讨论】:

  • 你可以尝试使用 boost::variant 来达到你的目的。
  • 向量是同质的,它们只能包含一种类型的值。你可以做一些丑陋的多态技巧来做你正在尝试的事情,但更好的答案是你正在寻找一个 std::tuple。如果您希望能够像这样迭代容器,则需要使用一些 boost::fusion 或 boost::hana - esque 元函数。这一切都假设您可以在编译时确定类型。
  • 我不是专家,但我首先想到的是创建一个vector of void* 我不知道这个设计有多好,但也许这可以解决问题。
  • 您不能创建包含引用的容器或异构容器。
  • @PRP 那真是个坏主意。你怎么知道原来的类型是什么?所以不可能回弹,整件事情都是无用的。

标签: c++ arrays vector reference


【解决方案1】:

你有两个问题。首先,一个容器不能包含不同类型的元素。其次,您不能将引用存储在容器中。

解决第一个问题的一种方法是使用 C++17 中的std::variant(或boost::variant)。要解决第二个问题,您可以使用std::reference_wrapper:

class Validate {
   using Uint8Ref   = std::reference_wrapper<uint8_t>;
   using Uint16Ref  = std::reference_wrapper<uint16_t>;
   using Uint32Ref  = std::reference_wrapper<int32_t>;
   using MemberType = std::variant<Uint8Ref, Uint16Ref, Uint32Ref>;

   std::vector<MemberType> members;
   uint8_t                 x;
   uint16_t                y;
   int32_t                 z;

public:
   Validate();
   void doSomething(uint8_t &member);
   void doSomething(uint16_t &member);
   void doSomething(int32_t &member);
};

Validate::Validate() : members({std::ref(x), std::ref(y), std::ref(z)}) {    
   for (auto member : members) {
      std::visit([this](auto member){this->doSomething(member);}, member);
   }
}

Live demo.

或者,您可以为可以存储在容器中的成员创建多态基类:

class MemberType {
public:
 virtual ~MemberType(){}
 virtual void accept(Validate& validate) = 0;
};

class Validate {    
   std::array<std::unique_ptr<MemberType>, 3> members;
   // as before...
};

template<typename T>
class MemberTypeImpl : public MemberType {
  T& member;
public:  
  MemberTypeImpl(T& member) : member(member){}
  void accept(Validate& validate) override {
    validate.doSomething(member);
  }
};

template<typename T>
std::unique_ptr<MemberType> make_member_type(T& member) {
  return std::make_unique<MemberTypeImpl<T>>(member);
}

Validate::Validate() 
  : members({make_member_type(x), make_member_type(y), make_member_type(z)}) {
   for (auto& member : members) {
      member->accept(*this);
   }
}

【讨论】:

  • 我实际上得到了它与 boost 元组一起工作,但事实证明,这种整体思维方式使代码变得比它必须的更难,最初的任务是从字符串中解码十六进制并得到它的几个值,当我可以从 substr() 中读取时,这是一种完全不必要的方式。
  • 感谢您的帮助,也很抱歉浪费您的时间。
  • @Tomzter 没问题,我考虑过元组解决方案,但迭代元组有点痛苦。
猜你喜欢
  • 2015-12-17
  • 2015-12-26
  • 1970-01-01
  • 2018-11-27
  • 2022-01-21
  • 2015-03-23
  • 2022-11-02
相关资源
最近更新 更多