将指向不同变量类型的指针传递给一个函数,并在以后重用它们进行赋值

Passing pointers to different variable types to a function and reuse them later for assignmet

在一个基于 GUI 的项目中,我需要 Page1 标记一个变量 要更改 并调用 Page2,Page2 读取用户的输入并用新值更新标记的变量。 变量类型始终不同,所有变量都由外部链接库保存。

如何在不为标记和设置器创建 fname_uint8、fname_uint16、fname_giventype 变体的情况下实现这一目标?

这个例子总结了场景:

有一个 VarHolder class 包含很多结构和很多变量,例如:

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

现在 class FirstStage 想要标记一个变量进行更改,并调用 class Committercommitter_instance 实例的成员

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

当然我不能做的是实现一个类型独立的"marker and retriever",它可以根据地址无缝更新变量。 非常感谢任何建议。

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.h


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

您可以在不使用(不安全)或使用 typeid 的情况下使用 void*

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

Live example