简体   繁体   English

使用来自联合数组的数据初始化std :: vector

[英]Initialise a std::vector with data from an array of unions

How might I initialise a std::vector from an array of structs, where the struct contains a union of different types. 我如何从结构数组初始化std :: vector,其中struct包含不同类型的并集。 In other words, the array is used to store a number of values of a specific type, which can be int, char* etc. 换句话说,该数组用于存储特定类型的多个值,可以是int,char *等。

This is my solution so far but I'm looking for a better approach: 到目前为止,这是我的解决方案,但我正在寻找更好的方法:

The convert function returns a vector<int> if it stores int s or a vector<std::string> if it stores char* . 如果存储int则convert函数返回vector<int>如果存储char*则返回vector<std::string>

The Value type below is a struct containing a union called value. 下面的Value类型是一个包含名为value的union的结构。 The Container class below points to a buffer of such Values. 下面的Container类指向此类值的缓冲区。

// union member getter
class Getter
{
public:

    void operator()(int8_t& i, const Value& value)
    {
        i = value.value.i;
    }

    void operator()(std::string& s, const Value& value)
    {
       s = std::string(value.value.s);
    }

    ...
};

template<class T>
std::vector<T> convert(Container* container)
{
    std::vector<T> c;
    c.reserve(container->nrOfValues);
    Getter g;
    for(int i=0;i<container->nrOfValues;i++)
    {
        T value;
        g(value, container->values[i]);
        c.push_back(value);
    }
    return c;
}

Your problem is the union gives a different name to each value, which causes the need for a function that converts a name to a type, such as Getter::operator() returning a type and getting a named member of the union. 你的问题是union为每个值提供了一个不同的名称,这导致需要一个将名称转换为类型的函数,例如Getter :: operator()返回一个类型并获取union的一个命名成员。

There isn't much you can do with this. 你无能为力。 You can save a variable declaration and a copy/string constructor on each item, but that's about it. 您可以在每个项目上保存变量声明和复制/字符串构造函数,但这就是它。

If you can't modify the original struct, you could initialize the vector with a length set of default value (which must be passed in), then iterate through using the getter as: 如果无法修改原始结构,则可以使用默认值的长度集(必须传入)初始化向量,然后使用getter迭代:

vector<T> v(length, defaultValue);
typename vector<T>::iterator iter = vec.begin();
for(int index = 0; *iter != vec.end() && index < length; ++iter, ++index) {
  converter(*iter, array[index]);
}

Notice that this starts getting cumbersome in iterating the index and the iterator and verifying both are still valid in case of an accident... 请注意,这在迭代索引和迭代器时开始变得麻烦,并且在发生事故时验证两者仍然有效...

If you can modify the original struct: 如果你可以修改原始结构:

class Ugly { // or struct, it doesn't matter
public:
  union {
    char* s;
    int i;
  } value;

  Ugly(char* s) {
    value.s = s;
  }

  Ugly (const int& i) {
    value.i = i;
  }

  operator std::string() const {
    return std::string(value.s);
  }

  operator int() const {
    return value.i;
  }
};

Then your for loop becomes: 然后你的for循环变为:

for(int i=0;i<container->nrOfValues;i++)
{
    c.push_back(container->values[i]);
}

Note: You might create the vector and pass it as an argument to the copy function since it involves copying the data over during the return. 注意:您可以创建向量并将其作为参数传递给复制函数,因为它涉及在返回期间复制数据。

If you like some template magic, you could do it slightly different way: 如果你喜欢一些模板魔术,你可以采用稍微不同的方式:

// Source union to get data from
union U
{
  int i;
  char* s;
  double d;
};

// Conversion type template function (declared only)
template <class T> T convert(const U& i_u);

// Macro for template specializations definition
#define FIELD_CONV(SrcType, DestField)\
template <> SrcType convert(const U& i_u)\
{ auto p = &DestField; return i_u.*p; }

// Defining conversions: source type -> union field to get data from
FIELD_CONV(int, U::i)
FIELD_CONV(std::string, U::s)
FIELD_CONV(double, U::d)

// Get rid of macro that not needed any more - just for macro haters ;-)
#undef FIELD_CONV

// Usage
template<class T> std::vector<T> convert(Container* container)
{
   std::vector<T> c;
   c.reserve(container->nrOfValues);
   for(int i = 0; i < container->nrOfValues; ++i)
     c.push_back(convert<T>(container->values[i])); 
   return c;
} 

The advantage of this approach - it is short, simple and easy to extend. 这种方法的优点 - 它简短,易于扩展。 When you add new field to union you just write another FIELD_CONV() definition. 将新字段添加到union时,只需编写另一个FIELD_CONV()定义。

Compiled example is here . 编译示例在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM