0

構造体の配列からstd::vectorを初期化するにはどうすればよいですか。ここで、構造体にはさまざまなタイプの和集合が含まれています。つまり、配列は、int、char*などの特定のタイプの値を格納するために使用されます。

これはこれまでの私の解決策ですが、より良いアプローチを探しています:

convert関数は、svector<int>を格納する場合はaを返し、を格納する場合はaを返します。intvector<std::string>char*

以下のValueタイプは、valueと呼ばれる共用体を含む構造体です。以下の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;
}
4

2 に答える 2

1

問題は、ユニオンが値ごとに異なる名前を付けることです。これにより、Getter :: operator()が型を返し、ユニオンの名前付きメンバーを取得するなど、名前を型に変換する関数が必要になります。

これでできることはあまりありません。変数宣言とコピー/文字列コンストラクターを各アイテムに保存できますが、それだけです。

元の構造体を変更できない場合は、デフォルト値の長さセット(渡される必要があります)を使用してベクトルを初期化し、ゲッターを次のように使用して反復することができます。

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

注:ベクトルを作成し、それを引数としてコピー関数に渡すことができます。これは、戻り時にデータをコピーする必要があるためです。

于 2012-09-12T17:28:23.690 に答える
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()定義を記述するだけです。

コンパイルされた例はここにあります。

于 2012-09-13T10:56:24.713 に答える