簡體   English   中英

可以使用模板在C ++中按名稱訪問Bitfield成員嗎?

[英]Can templates be used to access Bitfield members by name in C++?

可以使用模板按名稱訪問結構變量嗎? 有一個模板函數的示例,它允許設置給定結構的任意成員。 簡化示例:

#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;
};

問候,

MOX

編輯:如果我將代碼擴展到

#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方法需要#定義寄存器地址,寄存器中每個位的偏移量,然后保存一堆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傳輸時可能會出現錯誤,因此我想復制寄存器結構,更改一個或多個值,將其發送到設備,如果傳輸正常,用更改后的副本覆蓋寄存器結構。

首先,將您的set更改為:

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上面的member_t涉及的花式體操允許使用set({construct, the, value, here})語法。 我沒有對SETTER宏做同樣的事情,但是我可能可以做更多的工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM