c++ - 可以使用模板在 C++ 中按名称访问位字段成员吗?

标签 c++ c++11

Can templates be used to access struct variables by name?有一个模板函数的示例,允许设置给定结构的任意成员。 简化示例:

#include <iostream>
#include <ostream>
#include <string>


template < typename T, typename M, typename V >
void set(T *obj, M mem, V val)
{
    obj->*mem = val;
}


struct Obj1
{
    int a;
    double b;
};

struct Obj2
{
    std::string foo;
    float bar;
};


int main()
{
    Obj1 o1;
    o1.a=10;
    o1.b=10;
    Obj2 o2;
    o2.foo="foobarbaz";
    o2.bar=3.2f;

    std::cout<<"o1.a="<<o1.a<<", o1.b="<<o1.b<<std::endl;
    set(&o1, &Obj1::a, 30);
    std::cout<<"o1.a="<<o1.a<<", o1.b="<<o1.b<<std::endl;


    std::cout<<"o2.foo="<<o2.foo<<", o2.bar="<<o2.bar<<std::endl;
    set(&o2, &Obj2::foo, "example text");
    std::cout<<"o2.foo="<<o2.foo<<", o2.bar="<<o2.bar<<std::endl;

    return 0;
}

这按预期工作。但是,它不适用于位域,因为无法获取指向位域成员的指针。所以,我的问题是,有没有办法为位字段编写类似的内容?比如说,我想访问以下成员:

struct Obj3
{
    unsigned char first:3;
    unsigned char second:5;
};

问候,

莫克斯

编辑: 如果我将代码扩展为

#include <iostream>
#include <ostream>
#include <string>


template < typename T, typename M, typename V >
void set(T *obj, M mem, V val)
{
    obj->*mem = val;
}


struct Obj1
{
    int a;
    double b;
};

struct Obj2
{
    std::string foo;
    float bar;
};

struct Obj3
{
    unsigned char first:3;
    unsigned char second:5;
};



int main()
{
    Obj1 o1;
    o1.a=10;
    o1.b=10;
    Obj2 o2;
    o2.foo="foobarbaz";
    o2.bar=3.2f;

    Obj3 o3;
    o3.first=1;
    o3.second=1;

    std::cout<<"o1.a="<<o1.a<<", o1.b="<<o1.b<<std::endl;
    set(&o1, &Obj1::a, 30);
    std::cout<<"o1.a="<<o1.a<<", o1.b="<<o1.b<<std::endl;


    std::cout<<"o2.foo="<<o2.foo<<", o2.bar="<<o2.bar<<std::endl;
    set(&o2, &Obj2::foo, "example text");
    std::cout<<"o2.foo="<<o2.foo<<", o2.bar="<<o2.bar<<std::endl;

    std::cout<<"o3.first="<<o3.first<<", o1.second="<<o3.second<<std::endl;
    set(&o3, &Obj3::second, 2);
    std::cout<<"o3.first="<<o3.first<<", o1.second="<<o3.second<<std::endl;
    return 0;
}

我收到以下错误消息:

$ g++ main.cpp && ./a.out
main.cpp: In function ‘int main()’:
main.cpp:56:18: error: invalid pointer to bit-field ‘Obj3::second’
  set(&o3, &Obj3::second, 2);

编辑:(我的用例) 我编写了一种与只读 i2c 设备通信的驱动程序。 通常的旧 C 方法需要 #define-ing 寄存器地址、寄存器内每个位的偏移量,然后保存一堆 uint16_t my_register_whatever 值。访问将通过按位运算来完成。我想尝试一种更像 C++ 的方法:

struct __attribute__((__packed__))
{
    unsigned char address : 7;
    unsigned char DAC : 4;
    unsigned char ADC : 1;
    unsigned char MIC : 3;
    unsigned char LINE : 1;
} power_down_control;

这将增加类型安全性和更清晰、更易读的语法。 现在,由于我的 I²C 设备不允许读取,并且在进行 I²C 传输时可能会出现错误,因此我想复制寄存器结构,更改一个或多个值,将其发送到设备,如果传输顺利,用更改后的拷贝覆盖寄存器结构。

最佳答案

首先,将您的更改为:

template<class M>
struct member_type;
template<class T, class X>
struct member_type<T::*X> {
  using type=X;
};
template<class M>
using member_t = typename member_type<M>::type;

template<class T, class M>
struct set_t {
  T* t;
  M* m;
  template<class V>
  auto operator()(V&& v)const
  -> decltype(
    (std::declval<T* const&>(t)->*std::declval<M* const&>())
    =std::declval<V>()
  ) {
    return (t->*m) = std::forward<V>(v);
  }
  member_t<M*>& operator()(member_t<M*>&& v)const{
    return (t->*m) = std::move(v);
  }
};
template<class T, class M>
set_t<T,M> set(T* t, M* m) { return {t, m}; }

使用就变成:

auto setter = set(&o2, &Obj2::foo);
setter("example text");

set(&o2, &Obj2::foo)("example text");

在一行上。

我们的想法是,我们将设置对象的创建与设置分开。

然后我们可以为给定字段创建特定的设置对象。

#define SETTER(M) \
  [&](auto* t){
    return [t,&](auto&& v) {
      return (t->M) = decltype(v)(v);
    };
  }

用法如下:

auto setter = SETTER(second)(&o3);
setter(2);

SETTER(second)(&o3)(2);

简而言之。


顺便说一句,上面涉及 member_t 的花哨体操允许 set({construct, the, value, here}) 语法。我没有对 SETTER 宏做同样的事情,但我可能可以做更多的工作。

关于c++ - 可以使用模板在 C++ 中按名称访问位字段成员吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30334167/

相关文章:

c++ - QStringList::append() 性能不佳

c++ - 如何使用 Qt/C++ 打开和显示 PDF 文件?

c++ - Phoenix::bind for C++11 lambdas in boost::spirit::qi 语义 Action

c++ - std::atomic::compare_exchange_weak 的虚假失败,以防值等于预期

c++ - 在 C++ 中将字符字母转换为数字?

java - C++ 中的 Gsoap 错误

c++ - C++ 类中 const 属性的后期绑定(bind)?

c++ - 强制在编译时评估常量表达式?

c++ - 是否可以在 C++ 中自动生成析构函数?

c++ - 在 VC2015 中连接不匹配的字符串 WORKS - 如何?