Отражение в C ++ очень полезно, в случаях вам нужно запустить какой-то метод для каждого члена (например: сериализация, хеширование, сравнение). Я пришел с общим решением с очень простым синтаксисом:
struct S1
{
ENUMERATE_MEMBERS(str,i);
std::string str;
int i;
};
struct S2
{
ENUMERATE_MEMBERS(s1,i2);
S1 s1;
int i2;
};
Где ENUMERATE_MEMBERS - это макрос, который описан ниже (UPDATE):
Предположим, что мы определили функцию сериализации для int и std :: string:
void EnumerateWith(BinaryWriter & writer, int val)
{
//store integer
writer.WriteBuffer(&val, sizeof(int));
}
void EnumerateWith(BinaryWriter & writer, std::string val)
{
//store string
writer.WriteBuffer(val.c_str(), val.size());
}
И у нас есть общая функция рядом с «секретным макросом»;)
template<typename TWriter, typename T>
auto EnumerateWith(TWriter && writer, T && val) -> is_enumerable_t<T>
{
val.EnumerateWith(write); //method generated by ENUMERATE_MEMBERS macro
}
Теперь вы можете написать
S1 s1;
S2 s2;
//....
BinaryWriter writer("serialized.bin");
EnumerateWith(writer, s1); //this will call EnumerateWith for all members of S1
EnumerateWith(writer, s2); //this will call EnumerateWith for all members of S2 and S2::s1 (recursively)
Итак, имея макрос ENUMERATE_MEMBERS в определении структуры, вы можете создавать сериализацию, сравнение, хэширование и другие материалы без касания оригинального типа, единственное требование - внедрять метод «EnumerateWith» для каждого типа, который не перечислим, за каждый перечислитель (например, BinaryWriter). Обычно вам нужно реализовать 10-20 «простых» типов для поддержки любого типа в вашем проекте.
Этот макрос должен иметь нулевые служебные данные для создания / уничтожения структуры во время выполнения, а код T .EnumerateWith () должен генерироваться по требованию, что может быть достигнуто путем создания его встроенной функции шаблона, поэтому единственные накладные расходы во всей истории - это добавить ENUMERATE_MEMBERS (m1, m2, m3 ...) к каждой структуре, тогда как реализация определенного метода для каждого типа элемента является обязательным в любом решении, поэтому я не предполагаю, что это накладные расходы.
UPDATE: существует очень простая реализация макроса ENUMERATE_MEMBERS (однако его можно было бы немного расширить для поддержки наследование из перечислимой структуры)
#define ENUMERATE_MEMBERS(...) \
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) const { EnumerateWithHelper(enumerator, __VA_ARGS__ ); }\
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) { EnumerateWithHelper(enumerator, __VA_ARGS__); }
// EnumerateWithHelper
template<typename TEnumerator, typename ...T> inline void EnumerateWithHelper(TEnumerator & enumerator, T &...v)
{
int x[] = { (EnumerateWith(enumerator, v), 1)... };
}
// Generic EnumerateWith
template<typename TEnumerator, typename T>
auto EnumerateWith(TEnumerator & enumerator, T & val) -> std::void_t<decltype(val.EnumerateWith(enumerator))>
{
val.EnumerateWith(enumerator);
}
И вам не нужна сторонняя библиотека для этих 15 строк кода;)
Я думаю, что это может быть тем, что Вы ищете: НА пункте .
КОНФЛИКТА, Если Вы определяете свою таблицу как это:
CREATE TABLE table1(
id INTEGER PRIMARY KEY ON CONFLICT REPLACE,
field1 TEXT
);
Теперь, если Вы делаете ВСТАВКУ с идентификатором, который уже существует, SQLite автоволшебно ОБНОВЛЯЕТ вместо ВСТАВКИ.
Hth...
Лучший подход, который я знаю, должен сделать обновление, сопровождаемое вставкой. "Наверху выбора" необходимо, но это не ужасная нагрузка, так как Вы ищете на первичном ключе, который быстр.
необходимо быть в состоянии изменить ниже операторов с таблицей & имена полей, чтобы сделать то, что Вы хотите.
--first, update any matches
UPDATE DESTINATION_TABLE DT
SET
MY_FIELD1 = (
SELECT MY_FIELD1
FROM SOURCE_TABLE ST
WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
)
,MY_FIELD2 = (
SELECT MY_FIELD2
FROM SOURCE_TABLE ST
WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
)
WHERE EXISTS(
SELECT ST2.PRIMARY_KEY
FROM
SOURCE_TABLE ST2
,DESTINATION_TABLE DT2
WHERE ST2.PRIMARY_KEY = DT2.PRIMARY_KEY
);
--second, insert any non-matches
INSERT INTO DESTINATION_TABLE(
MY_FIELD1
,MY_FIELD2
)
SELECT
ST.MY_FIELD1
,NULL AS MY_FIELD2 --insert NULL into this field
FROM
SOURCE_TABLE ST
WHERE NOT EXISTS(
SELECT DT2.PRIMARY_KEY
FROM DESTINATION_TABLE DT2
WHERE DT2.PRIMARY_KEY = ST.PRIMARY_KEY
);
Если Вы обычно делаете обновления, я был бы..
, Если Вы обычно делаете, вставляет, я был бы
Этот способ, которым Вы избегаете выбора, и Вы являетесь транзакционно звуковыми на Sqlite.