按名称存储和引用变量列表

Store and reference a list of variables by name

本文关键字:引用 变量 列表 存储      更新时间:2023-10-16

我正在尝试创建一个库函数来存储指向各种类型的变量(int,char,String等)的指针,然后通过引用它们的名称来打印它们的值。

所以:

int a;
const char *b;
String c;
storeVar("a", &a);
storeVar("b", &b);
storeVar("c", &c);

后来:

printVar("a");
printVar("b");
printVar("c");

这里的诀窍是,我不想枚举用户可能调用库的所有潜在类型;也就是说,我想使用模板在编译时根据我在storeVar()调用中使用的类型生成必要的代码。

如果我枚举所有潜在的数据类型,我可以以一种相对简单(如果笨拙)的方式解决这个问题,无论是通过使用联合和类型枚举,还是通过按类型保留每个变量的单独列表......但我无法弄清楚如何解决它。

有什么想法吗? 我正在使用Arduino平台,因此我比在PC上受到更多的限制(例如,Boost可能不是一种选择)。


该解决方案基于Massimiliano Janes提供的代码,正在工作。 不幸的是,unordered_map在整个Arduino平台上不可用,所以我可能无法使用它。 但是,这只是一个存储细节,我相信无论变量如何存储,这种方法都会起作用。

// rst.h
#include <unordered_map>    
class Rst {    
private:
struct variable
{
virtual void print_me() const = 0;
};    
template<typename T>
struct variable_of_type: variable
{
T *var;    
variable_of_type(T *v) : var{v} { }    
void print_me() const override { 
Serial.println(*var); 
}
};    
public:    
template<typename T>
void store_var(const char *name, T *v) { 
varList[name] = new variable_of_type<T>(v);
}    
void print(const char *name) {
varList[name]->print_me();
}    
private:
std::unordered_map<const char*, variable*> varList;
};    

#include "rst.h"    
Rst rst;    
int q;
int a = 0;
const char* b = "hallo";    
void setup()
{
Serial.begin(115200);    
Serial.println("=====");    
rst.store_var("q", &q);    
rst.store_var("a", &a);
rst.store_var("b", &b);
q = 10;
rst.print("q");
rst.print("a");
rst.print("b");    
q=15;
rst.print("q");
}    
void loop() {
delay(1000);
}

Boost 主要只是标头,因此,除非您的平台缺乏语言级别支持,否则 boost 变体/任何/类型擦除/容器应该开箱即用......

无论如何,如果您仍然想编写自己的类型擦除解决方案,那么这个想法是在抽象接口后面封装"泛型"行为,并让虚拟调度机制调用实际的模板化实现,如下所示:

struct variable
{
virtual ~variable() = default;
virtual void print_me() const = 0;
};
template<typename T>
struct variable_of_type:
variable
{
T const& var;
variable_of_type(T const& v)
:var{v}{}
virtual void print_me() const override
{ std::cout << var << std::endl; }
};
template<typename T>
auto make_var(T const& v) // beware of v's lifetime !
{ return std::make_unique<variable_of_type<T>>(v); }
int main()
{
auto a = 0;
auto b = std::string{"hallo"};
auto vars = std::unordered_map<std::string,std::unique_ptr<variable>>{};
vars["a"] = make_var(a);
vars["b"] = make_var(b);
vars["a"]->print_me();
vars["b"]->print_me();
}

更准确地说,一个真正的类型擦除解决方案会将unique_ptr层隐藏在一些常规类型后面(例如,请参阅std::anystd::function<void()>,...),无论如何,我希望您了解基本想法...