Передача указателей на различные типы переменных в функцию и их повторное использование позже для assignmet

В проекте на основе графического интерфейса мне нужно Page1, чтобы пометить переменную быть измененным и вызовите Page2, Page2 читает ввод пользователя и обновляет помеченную переменную новым значением.
Тип переменной всегда различен, и все переменные хранятся во внешней связанной библиотеке.

Как этого добиться, не создавая варианты fname_uint8, fname_uint16, fname_giventype для маркеров и сеттеров?

Этот пример подводит итог сценария:

Здесь VarHolder класс, который содержит много структур с большим количеством переменных, например:

class VarHolder
{
public:
typedef struct {
int8_t var1;
int16_t var2;
int32_t var3;
char str1[40];
float var4;
} struct1_t;
/* ...continues... */

struct1_t struct1;
}

Сейчас класс FirstStage хочет пометить одну переменную для изменения, и вызывает член committer_instance экземпляр класса Committer

class FirstStage
{
/* ... */
void doFirstStage(void)
{
/* Globally defined committer instance */
g_committer_instance->mark_var_change(&varholder_instance->struct1.var1);
}
}

Committer::mark_var_change(T*) определяется следующим образом:

template <typename T>
void Committer::mark_var_change(T *var)
{
/* Store a pointer to the variable */
/* SAVE SOMEWHERE PRESERVING TYPE */ = var;
}

Член SecondStageнаконец, хочет использовать доступное теперь значение, чтобы обновить переменную, помеченную для изменения через тот же g_committer_instance, как это:

class SecondStage
{
/* ... */
template <typename T>
void doSecondStage(T new_value)
{
g_committer_instance->commit_change(new_value);
}
}

где Committer::commit_change(T) определяется следующим образом:

template <typename T>
void Committer::commit_change(T new_value)
{
/* Dereferencing the previously stored pointer */
*(/*WHATEVER I STORED BEFORE*/) = new_value;
}

Конечно, я не могу реализовать независимый от типа «маркер и ретривер», который может плавно обновлять переменную в зависимости от их адреса.
Любое предложение очень ценится.

MCVE

### varholder.h
#include <stdint.h>
class VarHolder
{
public:
VarHolder() {}
virtual ~VarHolder() {}
typedef struct
{
int8_t var1;
uint8_t var2;
int64_t var3;
char str1[40];
} struct1_t;

struct1_t struct1;
}

### firststage.h
#include global.h

class FirstStage
{
public:
FirstStage() {}
~FirstStage() {}

void doFirstStage(void)
{
/* Globally defined committer instance */
g_committer_instance->mark_var_change(&varholder_instance->struct1.var1);
}
}

### secondstage.h
#include global.h

class SecondStage
{
public:
SecondStage() {}
~SecondStage() {}
template <typename T>
void doSecondStage(T new_value)
{
g_committer_instance->commit_change(new_value);
}
}
### committer.h
#include global.h

class Committer
{
public:
Committer() {}
~Committer() {}
template <typename T>
void Committer::mark_var_change(T *var)
{
/* Store a pointer to the variable */
/* SAVE SOMEWHERE PRESERVING TYPE */ = var;
}

template <typename T>
void Committer::commit_change(T new_value)
{
/* Dereferencing the previously stored pointer */
*(/*WHATEVER I STORED BEFORE*/) = new_value;
}
}### global.h

#include varholder.h
#include committer.h

extern Committer *g_committer_instance;
extern VarHolder *varholder_instance;

### main.cpp

#include global.h
#include varholder.h
#include firststage.h
#include secondstage.hCommitter *g_committer_instance;
VarHolder *varholder_instance;

int main()
{
g_committer_instance = new Committer();
varholder_instance = new VarHolder();
FirstStage *fstage = new FirstStage();
SecondStage *sstage = new SecondStage();

int8_t var_new = 100;

/* First stage */
fstage->doFirstStage();
/* Second stage */
sstage->doSecondStage(var_new);

return 0;
}

0

Решение

Вы можете использовать void* без (небезопасно) или с typeid:

class Committer
{
public:

template <typename T>
void mark_var_change(T *var)
{
mPointer = var;
mTypeInfo = &typeid(T*);
}

template <typename T>
void commit_change(T new_value)
{
if (*mTypeInfo != typeid(T*)) {
throw std::runtime_error("Bad type");
}
if (mPointer == nullptr) {
throw std::runtime_error("nullptr was stocked");
}
*reinterpret_cast<T*>(mPointer) = new_value;
}

private:
void* mPointer = nullptr;
const std::type_info* mTypeInfo = nullptr;
};

или безопаснее boost::any которые сами управляют типом:

class Committer
{
public:

template <typename T>
void mark_var_change(T *var)
{
mPointer = var;
}

template <typename T>
void commit_change(T new_value)
{
T* pointer = boost::any_cast<T*>(mPointer); // throw with bad type
if (pointer == nullptr) {
throw std::runtime_error("nullptr was stocked");
}
*pointer = new_value;
}

private:
boost::any mPointer;
};

Живой пример

0

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector