2016-01-25 100 views
1

我需要使用訪問結構內聯合的語法方面的幫助,如下所示。編譯器抱怨我需要必須命名下面的'innerStruct'定義,而不是具有匿名內部結構。有人可以請解釋規則,以及如何初始化構造函數字段並命名位域元素。我有一個live coliru demo來顯示代碼。如何使用具有匿名結構的匿名C++聯合

不幸的是,代碼不能編譯,因爲它表明了以下錯誤:

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out 
main.cpp: In constructor 'Foo::Foo(uint8_t, uint8_t)': 
main.cpp:38:11: error: class 'Foo' does not have any field named 'asUint8' 
     , asUint8(aBitFields) 
     ^
main.cpp: In function 'std::ostream& operator<<(std::ostream&, const Foo&)': 
main.cpp:54:83: error: 'const struct Foo' has no member named 'innerStruct' 
      << "], mA[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mA 
                       ^
main.cpp:55:83: error: 'const struct Foo' has no member named 'innerStruct' 
      << "], mB[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mB 
                       ^
main.cpp:56:83: error: 'const struct Foo' has no member named 'innerStruct' 
      << "], mC[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mC 
                       ^
main.cpp:57:83: error: 'const struct Foo' has no member named 'innerStruct' 
      << "], mD[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mD 
                       ^

struct Foo { 
    // fields 
    uint8_t mType; 
    union innerUnion_t { 
     struct innerStruct_t { 
      uint8_t mA : 2; 
      uint8_t mB : 1; 
      uint8_t mC : 2; 
      uint8_t mD : 3; 
     } innerStruct; 
     uint8_t asUint8; 
    } innerUnion; 

    // constructor 
    explicit Foo() = default; 

    // constructor 
    explicit Foo(
     const uint8_t aType, 
     const uint8_t aBitFields) 
     : mType(aType) 
     , asUint8(aBitFields) 
    {} 

    /** 
    * Stream insert operator<p> 
    * 
    * @param os  [in,out] output stream 
    * @param rhs [in] Foo to send to the output 
    *    stream. 
    * 
    * @return a reference to the updated stream 
    */ 
    friend std::ostream& operator<<(
     std::ostream& os, const Foo& rhs) { 
     os << "Foo" 
      << ": type[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.mType 
      << "], mA[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mA 
      << "], mB[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mB 
      << "], mC[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mC 
      << "], mD[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mD 
      << "]"; 
     return os; 
    } 
}; 

編輯

注:以下有輕微的變化,以結構定義建議的答案,我也有一個關於什麼語法應該是初始化或引用位字段mA - > mD的額外問題,我嘗試在構造函數中使用以下語法,但它也不編譯。我試圖命名innerUnion和顯式地引用其命名嵌套結構作爲innerUnion.innerStruct.mA(1) - 見second live demo

它提供了以下錯誤:

main.cpp: In constructor 'Foo::Foo(uint8_t, uint8_t)': 
main.cpp:39:21: error: expected '(' before '.' token 
     , innerUnion.innerStruct.mA(1) 
        ^
main.cpp:39:21: error: expected '{' before '.' token 
+1

注意:您的字段名稱表明您打算使用* union別名*。這在標準C++中是未定義的行爲;只能讀最近寫的工會會員。位字段的順序和間隔也是實現定義的。 –

回答

2

你只需要刪除您的代碼中的某些字詞:

#include <memory> 
#include <iomanip> 
#include <iostream> 
#include <string> 
#include <vector> 

template<typename T> 
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) 
{ 
    for (auto& el : vec) 
    { 
     os << el << ' '; 
    } 
    return os; 
} 

struct Foo { 
    // fields 
    uint8_t mType; 
    union { 
     struct { 
      uint8_t mA : 2; 
      uint8_t mB : 1; 
      uint8_t mC : 2; 
      uint8_t mD : 3; 
     } innerStruct; 
     uint8_t asUint8; 
    }; 

    // constructor 
    explicit Foo() = default; 

    // constructor 
    explicit Foo(
     const uint8_t aType, 
     const uint8_t aBitFields) 
     : mType(aType) 
     , asUint8(aBitFields) 
    {} 

    /** 
    * Stream insert operator<p> 
    * 
    * @param os  [in,out] output stream 
    * @param rhs [in] Foo to send to the output 
    *    stream. 
    * 
    * @return a reference to the updated stream 
    */ 
    friend std::ostream& operator<<(
     std::ostream& os, const Foo& rhs) { 
     os << "Foo" 
      << ": type[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.mType 
      << "], mA[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mA 
      << "], mB[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mB 
      << "], mC[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mC 
      << "], mD[0x" << std::setw(2) << std::setfill('0') << std::hex << rhs.innerStruct.mD 
      << "]"; 
     return os; 
    } 
}; 

int main() 
{ 
    std::vector<std::string> words = { 
     "Hello", "from", "GCC", __VERSION__, "!" 
    }; 
    std::cout << words << std::endl; 

    auto pFoo = std::make_unique<Foo>(); 
    std::cout << *pFoo << std::endl; 
} 
+0

謝謝,但我也許沒有問這個,但在構造函數中,我怎樣才能明確地初始化命名位字段 - 正如你所看到的,我初始化asUnit9字段,它與所有組合位字段是同義詞。 – johnco3

+0

@ johnco3:'Foo :: Foo():innerStruct.mA(3){}' –

+0

我在頭文件中試過如下,但它不能編譯http://coliru.stacked-crooked.com/a/ ca08f988c49fe343 - 雖然http://coliru.stacked-crooked.com/a/0417323b5ee50539 – johnco3