любой шаблонный, общий способ скопировать подобную структуру данных в C ++? - PullRequest
2 голосов
/ 02 марта 2012

У меня есть ряд из нескольких аналогичных структур, например,

map<key1, attr1>; map<key2, attr2>; ..., 

. Между тем, в корреспонденции, ряд массивов,

// JUST TO SHOW THE IDEA, NOT SYNTAX CORRECT
class {key_1; attr_1;} array [#]; class {key_2; attr_2;} array [#]; ...,

, а keyX и key_X имеют похожую структуру, а также attr, например,

struct key1 {int k1;}; class key_1 {int k_1;};
struct key2 {int k1; int k2;}; class key_2 {int k_1; int k_2;};
   ...
struct attr1 {int a1; int a2;}; class attr_1 {int a_1; int a_2;};

Мне нужно написать функцию, например, перегрузить оператор присваивания, чтобы преобразовать данные из map_series в другие и наоборот.

Таким образом, вместо того, чтобы делать это сопоставлять по карте , ключ по ключу и int по int , существует ли некоторый шаблонный способсделать это, чтобы код был общим или сохранить больше строк кода?Что может быть разумным способом сделать это?

РЕДАКТИРОВАТЬ 1:

К сожалению, одно ограничение из-за нашей унаследованной системы, преобразование типов между struct, например, key1,key_1, не работает как примитивы C ++, поэтому должна быть предусмотрена функция преобразования.

РЕДАКТИРОВАТЬ 2:

вдохновленный ответом JN, возможно ли иметь что-то вроде:

template <class KeyMap, class ValueMap, class KeyArr, class ValueArr> void convert (map<KeyMap, ValueMap>, class {KeyArr, ValueArr} array[]){};

как обобщить преобразование для ключаи аттр?как

template <class KeyMap, class KeyArr> void convert_key(KeyMap, KeyArr){} 

1 Ответ

3 голосов
/ 02 марта 2012

Хорошо, давайте предположим, что у нас есть это:

map<KeyTypeM, ValueTypeM> m1;
struct Type1 {
    KeyTypeS Key;
    ValueTypeS Value;
};

Давайте сначала определим функцию преобразования:

Type1 ConvType1(const KeyTypeM& key, const ValueTypeM& value)
{
    Type1 result;
    result.Key = f(key); // user dependent
    result.Value = f(value); // user dependent

    return result;
}

Тогда в C ++ вы не можете возвращать массивы. На самом деле вы обычно не работаете с массивом, люди обычно предпочитают std::vector. (Если вам действительно нужен массив, вам нужно выделить его и вернуть указатель на него или обернуть его в умный указатель) Тогда достаточно просмотреть значения на карте и вставить их в вектор:

vector<Type1> ConvertType1(map<KeyTypeM, ValueTypeM>& input)
{
    vector<Type1> result;
    for (auto& pair : input) // assumes C++11
        result.push_back( ConvType1(pair.first, pair.second) );
    return result;
}

note : если у вас нет компилятора C ++ 11, используйте:

for (map<KeyTypeM, ValueTypeM>::iterator it = m.begin(); it != m.end(); ++it)
    result.push_back( ConvType1(it->first, it->second) );

Это сделает работу для ОДНОЙ карты и одного типа. Теперь мы можем обобщить функцию преобразования, используя шаблоны:

template <class OutType, class KeyType, class ValueType, class Converter>
vector<OutType> Convert(map<KeyType, ValueType>& input, Converter conv)
{
    vector<OutType> result;
    for (auto& pair : input)
        result.push_back( conv(pair.first, pair.second) );
    return result;
}

И используйте это так:

auto v1 = Convert<Type1>(m1, &ConvertType1);
auto v2 = Convert<Type2>(m2, &ConvertType2);
...

Вы можете пойти дальше, создав список типов для преобразования, используя boost::mpl, но это должно быть в другом вопросе.

РЕДАКТИРОВАТЬ: обобщить преобразование типов

Как вы упомянули, нет общего способа преобразования типов, нам нужно написать все функции преобразования. Поэтому единственное, что мы можем сделать, - это сделать его более элегантным, реализовав операторы неявного преобразования, такие как:

struct KeyTypeM
{
     ... // normal members
     operator KeyTypeS() const
     {
         // do the conversion here
     }
};

 // suppose we have the same for ValueTypeM and ValueTypeS

 // We can now use a single convert function:

 template <class OutType, class KeyTypeM, class ValueType M>
 OutType ConvertToStruct(const KeyTypeM& key, const ValueTypeM& value)
 {
      OutType result;
      result.Key = key;      // will call the implicit conversion
      result.Value = value;
      return result;
 }

Это упрощает нашу функцию преобразования (обновлена ​​с учетом массива)

template <class OutType, class KeyType, class ValueType>
void Convert(map<KeyType, ValueType>& input, OutType out[])
{
    // out must have been initialized to a proper size to hold all the elements.
    unsigned cursor = 0;
    for (map<KeyTypeM, ValueTypeM>::iterator it = m.begin(); it != m.end(); ++it, ++cursor)
        out[cursor] = ConvertToStruct<OutType>(it->first, it->second);
}

РЕДАКТИРОВАТЬ 2: Мы можем использовать std::pair для обобщения структуры массива:

 template <class OutType, class KeyTypeM, class ValueType M>
 OutType ConvertToStruct(const KeyTypeM& key, const ValueTypeM& value)
 {
      OutType result;
      result.first = key;      // will call the implicit conversion
      result.second = value;
      return result;
 }

template <class OutKey, class OutValue, class KeyType, class ValueType>
void Convert(map<KeyType, ValueType>& input, std::pair<OutKey, OutValue> out[])
{
    // out must have been initialized to a proper size to hold all the elements.
    unsigned cursor = 0;
    for (map<KeyTypeM, ValueTypeM>::iterator it = m.begin(); it != m.end(); ++it, ++cursor)
        out[cursor] = ConvertToStruct<OutType>(it->first, it->second);
}

 // Use this way:

 std::pair<OutKey, OutValue> arr[m.size()];
 Convert(m, arr);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...