2012-09-12 72 views
0

如何从结构数组中初始化std :: vector,其中struct包含不同类型的联合。换句话说,该数组用于存储特定类型的多个值,可以是int,char *等。使用来自数组的数据初始化std :: vector

这是我的解决方案,但我正在寻找更好的方法:

如果转换函数存储int,则返回vector<int>;如果存储char*,则转换函数返回vector<std::string>

下面的值类型是一个包含称为值的联合的结构。下面的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; 
} 
+0

请说明。 1.容器保证只包含具有单一类型值的联合和2.检查哪些类型的容器值是(确定'T'类型)不是“转换”责任并在其他地方完成? – Rost

+0

@Rost容器保证只包含单个类型的值。关于容器包含的类型不是convert的责任。 – Baz

回答

1

你的问题是工会给出了不同的名称,每个值,这导致了一个名称转换为一个类型,如消气::运算符(功能的需要)返回一个类型,并得到一个名为工会成员。

你可以用这个做很多事。您可以在每个项目上保存一个变量声明和一个复制/字符串构造函数,但这就是它。

如果无法修改原始结构,则可以初始化与长度设定默认值(其必须被传递)载体中,然后通过使用吸气剂作为迭代:

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]); 
} 

通知这开始变得繁琐的迭代指数和迭代器和验证都仍然在发生事故的情况下,有效的...

如果你可以修改原来的结构:

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; 
    } 
}; 

那么你的for循环变成:

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

注意:您可以创建的载体,并作为参数传递给复制功能,因为它涉及到返回时在复制数据。

+0

感谢您的回复!为什么在for循环中包含* iter!= vec.end()&& index Baz

+0

为什么用默认值创建矢量(我如何在我的模板函数中建立它们)而不是预留内存呢? – Baz

+0

@Baz你正在迭代两件事情,它可能只是有人搞砸了。你可以通过在循环之前加以简化:if(vec.length()!= length){/ *句柄错误* /}。 –

1

如果你喜欢一些模板魔术,你能做到这一点的方式略有不同:

// 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; 
} 

这种方法的优点 - 它短,操作简单,易于扩展。当你向联合添加新的字段时,你只需编写另一个FIELD_CONV()定义。编号示例为here

+0

我真的不喜欢宏...诚然,我可能只是在现实生活中这样做,但我真的,真的不喜欢宏;-)在现实生活中,我们经常做我们不喜欢的事情。 .. –

+0

@JonathanSeng增加了宏观undef - 只为你:-) – Rost

+0

好吧,这让我感觉好一点。 :-)但是,我仍然恨他们;-)对不起。太多的错误和糟糕的代码......正如我所说,我可能会在现实生活中这样做,但我不喜欢它。 –

相关问题