可以使用模板按名称访问结构变量吗?
假设我有一个这样的结构:
Let's suppose I have a struct like this:
struct my_struct
{
int a;
int b;
}
我有一个函数,它应该为a"或b"设置一个新值.此函数还需要指定要设置的变量.一个典型的例子是这样的:
I have a function which should set a new value for either "a" or "b". This function also requires to specify which variable to set. A typical example would be like this:
void f(int which, my_struct* s, int new_value)
{
if(which == 0)
s->a = new_value;
else
s->b = new_value;
}
由于我不会在这里写的原因,我无法将指向 a/b 的指针传递给 f.所以我不能用 my_struct::a 或 my_struct::b 的地址调用 f.我不能做的另一件事是在 my_struct 中声明一个向量 (int vars[2]) 并将一个整数作为索引传递给 f.基本上在 f 我需要按名称访问变量.
For reasons I won't write here I cannot pass the pointer to a/b to f. So I cannot call f with address of my_struct::a or my_struct::b. Another thing I cannot do is to declare a vector (int vars[2]) within my_struct and pass an integer as index to f. Basically in f I need to access the variables by name.
前面例子的问题是,我打算在未来向 struct 添加更多变量,在这种情况下,我会记得向 f 添加更多 if 语句,这不利于可移植性.我可以做的一件事是将 f 写成一个宏,如下所示:
Problem with previous example is that in the future I plan to add more variables to struct and in that case I shall remember to add more if statements to f, which is bad for portability. A thing I could do is write f as a macro, like this:
#define FUNC(which)
void f(my_struct* s, int new_value)
{
s->which = new_value;
}
然后我可以调用 FUNC(a) 或 FUNC(b).
and then I could call FUNC(a) or FUNC(b).
这行得通,但我不喜欢使用宏.所以我的问题是:有没有办法使用模板而不是宏来实现相同的目标?
This would work but I don't like using macros. So my question is: Is there a way to achieve the same goal using templates instead of macros?
编辑:我将尝试解释为什么我不能使用指针并且我需要按名称访问变量.基本上,结构包含系统的状态.该系统需要在请求时撤消"其状态.撤消是使用名为 undo_token 的接口处理的,如下所示:
EDIT: I'll try to explain why I cannot use pointers and I need access to variable by name. Basically the structure contains the state of a system. This systems needs to "undo" its state when requested. Undo is handled using an interface called undo_token like this:
class undo_token
{
public:
void undo(my_struct* s) = 0;
};
因此,由于多态性,我无法将指针传递给 undo 方法(mystruct 也包含其他类型的变量).
So I cannot pass pointers to the undo method because of polymorphism (mystruct contains variables of other types as well).
当我向结构中添加一个新变量时,我通常也会添加一个新类,如下所示:
When I add a new variable to the structure I generally also add a new class, like this:
class undo_a : public undo_token
{
int new_value;
public:
undo_a(int new_value) { this->new_value = new_value; }
void undo(my_struct *s) { s->a = new_value}
};
问题是我在创建令牌时不知道指向 s 的指针,所以我无法在构造函数中保存指向 s::a 的指针(这可以解决问题)."b" 的类是相同的,只是我必须写 "s->b" 而不是 s->a
Problem is I don't know pointer to s when I create the token, so I cannot save a pointer to s::a in the constructor (which would have solved the problem). The class for "b" is the same, just I have to write "s->b" instead of s->a
也许这是一个设计问题:我需要每个变量类型一个撤消令牌,而不是每个变量一个......
Maybe this is a design problem: I need an undo token per variable type, not one per variable...
推荐答案
#include <iostream>
#include <ostream>
#include <string>
struct my_struct
{
int a;
std::string b;
};
template <typename TObject, typename TMember, typename TValue>
void set( TObject* object, TMember member, TValue value )
{
( *object ).*member = value;
}
class undo_token {};
template <class TValue>
class undo_member : public undo_token
{
TValue new_value_;
typedef TValue my_struct::* TMember;
TMember member_;
public:
undo_member(TMember member, TValue new_value):
new_value_( new_value ),
member_( member )
{}
void undo(my_struct *s)
{
set( s, member_, new_value_ );
}
};
int main()
{
my_struct s;
set( &s, &my_struct::a, 2 );
set( &s, &my_struct::b, "hello" );
std::cout << "s.a = " << s.a << std::endl;
std::cout << "s.b = " << s.b << std::endl;
undo_member<int> um1( &my_struct::a, 4 );
um1.undo( &s );
std::cout << "s.a = " << s.a << std::endl;
undo_member<std::string> um2( &my_struct::b, "goodbye" );
um2.undo( &s );
std::cout << "s.b = " << s.b << std::endl;
return 0;
}
相关文章