問題描述
假設我有一個這樣的結構:
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;
}
這篇關于可以使用模板按名稱訪問結構變量嗎?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!