Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板可以用于按名称访问结构变量吗?_C++_Templates - Fatal编程技术网

C++ 模板可以用于按名称访问结构变量吗?

C++ 模板可以用于按名称访问结构变量吗?,c++,templates,C++,Templates,假设我有一个这样的结构: struct my_struct { int a; int b; } void f(int which, my_struct* s, int new_value) { if(which == 0) s->a = new_value; else s->b = new_value; } #define FUNC(which) void f(my_struct* s, int new_value) \ { \

假设我有一个这样的结构:

struct my_struct
{
  int a;
  int b; 
}
void f(int which, my_struct* s, int new_value)
{
  if(which == 0)
     s->a = new_value;
  else
     s->b = new_value; 
}
#define FUNC(which)
void f(my_struct* s, int new_value) \
{ \
        s->which = new_value; \
} 
class undo_token
{
public:
   void undo(my_struct* s) = 0;
};
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}
};
print_member<age>(person);
我有一个函数,它应该为“a”或“b”设置一个新值。此函数还需要指定要设置的变量。典型的例子如下:

struct my_struct
{
  int a;
  int b; 
}
void f(int which, my_struct* s, int new_value)
{
  if(which == 0)
     s->a = new_value;
  else
     s->b = new_value; 
}
#define FUNC(which)
void f(my_struct* s, int new_value) \
{ \
        s->which = new_value; \
} 
class undo_token
{
public:
   void undo(my_struct* s) = 0;
};
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}
};
print_member<age>(person);
由于某些原因,我无法将指向a/b的指针传递给f。所以我不能用我的结构::a或结构::b的地址调用f。 我不能做的另一件事是在我的_结构中声明一个向量(int vars[2]),并将一个整数作为索引传递给f。基本上,在f中,我需要按名称访问变量

前面示例的问题是,将来我计划向struct添加更多变量,在这种情况下,我将记住向f添加更多if语句,这不利于可移植性。 我可以做的一件事是将f写成宏,如下所示:

struct my_struct
{
  int a;
  int b; 
}
void f(int which, my_struct* s, int new_value)
{
  if(which == 0)
     s->a = new_value;
  else
     s->b = new_value; 
}
#define FUNC(which)
void f(my_struct* s, int new_value) \
{ \
        s->which = new_value; \
} 
class undo_token
{
public:
   void undo(my_struct* s) = 0;
};
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}
};
print_member<age>(person);
然后我可以调用FUNC(a)或FUNC(b)

这会起作用,但我不喜欢使用宏。 所以我的问题是:有没有办法用模板而不是宏来实现同样的目标

编辑:我将尝试解释为什么我不能使用指针,我需要按名称访问变量。 基本上,结构包含系统的状态。此系统需要在请求时“撤消”其状态。使用名为Undo_token的接口处理Undo,如下所示:

struct my_struct
{
  int a;
  int b; 
}
void f(int which, my_struct* s, int new_value)
{
  if(which == 0)
     s->a = new_value;
  else
     s->b = new_value; 
}
#define FUNC(which)
void f(my_struct* s, int new_value) \
{ \
        s->which = new_value; \
} 
class undo_token
{
public:
   void undo(my_struct* s) = 0;
};
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}
};
print_member<age>(person);
因此,由于多态性(mystruct也包含其他类型的变量),我无法向undo方法传递指针

当我向结构中添加一个新变量时,我通常也会添加一个新类,如下所示:

struct my_struct
{
  int a;
  int b; 
}
void f(int which, my_struct* s, int new_value)
{
  if(which == 0)
     s->a = new_value;
  else
     s->b = new_value; 
}
#define FUNC(which)
void f(my_struct* s, int new_value) \
{ \
        s->which = new_value; \
} 
class undo_token
{
public:
   void undo(my_struct* s) = 0;
};
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}
};
print_member<age>(person);
问题是,当我创建令牌时,我不知道指向s的指针,所以我无法在构造函数中保存指向s::a的指针(这会解决问题)。 “b”的类是相同的,只是我必须写“s->b”而不是s->a


也许这是一个设计问题:我需要每个变量类型一个撤销标记,而不是每个变量一个…

您不能使用模板来解决这个问题,但为什么首先要使用结构?这似乎是将名称映射到值的std::map的理想用途。

我不确定为什么不能使用指针,所以我不知道这是否合适,但请看一下,它描述了一种方法,可以将指针传递到不直接指向成员的结构/类的数据成员,但随后绑定到结构/类指针。(在海报编辑后添加强调,解释为什么不能使用指针)

这样,您就不会向成员传递指针,而是更像是对象中的偏移量。

\include
#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;
}
#包括 #包括 结构我的结构 { INTA; std::字符串b; }; 模板 无效集(TObject*对象、TMember成员、TValue值) { (*对象)。*成员=值; } 类undo_标记{}; 模板 类undo_成员:公共undo_令牌 { t价值新的价值; typedef TValue my_struct::*t成员; t成员成员; 公众: 撤消成员(t成员,t值新值): 新值(新值), 委员(委员) {} 作废撤消(我的结构*s) { 集合(s、成员、新值); } }; int main() { 我的结构; 集合(&s,&my_struct::a,2); 集合(&s,&my_struct::b,“hello”);
std::cout听起来您正在寻找的东西被称为“”,是的,它通常是通过一些模板和宏的组合来实现的。请注意,反射解决方案通常是混乱的,令人讨厌,因此在深入研究代码之前,您可能想对它们进行一些研究,以确定这是否是您真正想要的


谷歌“C++反射模板”的第二个热门话题是一篇关于“”的论文。这应该会让你开始。即使它不是你想要的,它也可能会为你提供一种解决问题的方法。

根据你的描述,我猜你无法重新定义结构

如果您这样做了,我建议您使用Boost.Fusion来描述带有模板命名字段的结构。有关这方面的更多信息,请参阅。这两种结构实际上可能是兼容的(内存中的组织相同),但我非常确定,无法从标准中获得这样的保证

如果你不这样做,你可以创建一个对结构的补充,让你可以像关联元组一样访问字段,但这可能有点口头化

编辑


现在很清楚,您可以按照自己的方式定义结构。因此,我绝对建议您使用boost.fusion。

要回答确切的问题,确实有,但它相当复杂,而且纯粹是编译时的事情。(如果您需要运行时查找,请使用指向成员的指针——根据您更新的问题,您可能误解了它们的工作原理。)

首先,您需要一些可以在编译时用来表示“成员名称”的内容。在编译时元编程中,除了整数以外的所有内容都必须用类型来表示。因此,您将使用类型来表示成员

例如,一个integer类型的成员存储一个人的年龄,另一个用于存储他们的姓氏:

struct age { typedef int value_type; };
struct last_name { typedef std::string value_type; };
然后您需要一个类似于
map
的东西,它在编译时进行查找。我们称之为
ctmap
。让我们最多支持8个成员。首先,我们需要一个占位符来表示缺少字段:

struct none { struct value_type {}; };
然后我们可以向前声明
ctmap
的形状:

template <
    class T0 = none, class T1 = none,
    class T2 = none, class T3 = none,
    class T4 = none, class T5 = none,
    class T6 = none, class T7 = none
    >
struct ctmap;
这类似于在
映射中查找,但在编译时使用字段命名类作为键

这意味着我们也可以这样做:

template <class TMember>
void print_member(ctmap<last_name, age> &person)
{
    std::cout << person[TMember()] << std::endl;
}
模板
无效打印成员(ctmap和人员)
{

std::cout我想不出为什么在创建undo命令时,您不能手头有所有的东西。您希望能够撤销的东西,您已经完成了。因此,我相信在创建undo命令时,您可以使用指向类成员的指针,甚至指向特定类实例的字段的指针

你的编辑部分是对的。这是一个设计问题。

很好,但是