2017-07-21 44 views
1

我有一個我經常用於枚舉包裝的類,但是這需要一個cpp文件。誰能告訴我如何使用constexpr在枚舉類包裝類中定義靜態constexpr值

頭文件如下:

// Extend-able in the future 
class CDUVariable { 
public: 
    enum Value { 
     baud, firmware, type, serial 
    }; 
    static const CDUVariable Baud, Firmware, Type, Serial; 

    /// Comparison operator (used for strict weak ordering). 
    bool operator<(const CDUVariable& rhs) const { 
     return mValue < rhs.mValue; 
    } 

    /// Integral operator cast for switch statements (cast to named enum). 
    operator const Value() const { 
     return mValue; 
    } 

    /// Serialized version of the enum. 
    std::string getStringVal() const { 
     return mStringVal; 
    } 
    static const std::set<CDUVariable>& getValues() { 
     static std::set<CDUVariable> gValues; 
     if (gValues.empty()) { 
      gValues.insert(Baud); 
      gValues.insert(Firmware); 
      gValues.insert(Type); 
      gValues.insert(Serial); 
     } 
     return gValues; 
    } 
    static CDUVariable valueOf(const std::string& rStringVal) { 
     for (const auto& next : getValues()) { 
      if (next.getStringVal() == rStringVal) { 
       return next; 
      } 
     } 
     throw std::invalid_argument(
      "Illegal Argument: " + rStringVal); 
    } 
private: 
    CDUVariable(const Value& rValue, const std::string& rStringVal) 
     : mValue(rValue) 
     , mStringVal(rStringVal) 
    {} 
    Value mValue; 
    std::string mStringVal; 
}; 

和cpp文件是:

const CDUVariable CDUVariable::Baud(baud, "0"); 
const CDUVariable CDUVariable::Firmware(firmware, "1"); 
const CDUVariable CDUVariable::Type(type, "2"); 
const CDUVariable CDUVariable::Serial(serial, "3"); 

我想知道是否可以使用新的constexpr語法初始化頭文件中的所有內容。我遇到了語法問題。

我試過前綴修改標題如下:

// Extend-able in the future 
class CDUVariable { 
public: 
    constexpr enum Value { 
     baud, firmware, type, serial 
    }; 
    constexpr static CDUVariable Baud(baud, "0") Firmware(firmware, "1"), Type(type, "2"), Serial(serial, "3"); 

但是這最終給了我一堆錯誤。我想知道如何遷移到新的constexpr語法,並且這樣做的好處在於,我可以發佈僅包含這些枚舉類型類的僅包含頭文件的庫。

2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C2061: syntax error: identifier 'baud' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C3646: 'Firmware': unknown override specifier 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C2059: syntax error: '(' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(147): error C2143: syntax error: missing ')' before ';' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(147): error C2098: unexpected token after data member 'mValue' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(147): error C2059: syntax error: ')' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(111): error C2065: 'mValue': undeclared identifier 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(111): error C2039: 'mValue': is not a member of 'CDUVariable' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(116): error C2065: 'mValue': undeclared identifier 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(126): error C3867: 'CDUVariable::Baud': non-standard syntax; use '&' to create a pointer to member 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(127): error C2065: 'Firmware': undeclared identifier 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(128): error C2065: 'Type': undeclared identifier 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(129): error C2065: 'Serial': undeclared identifier 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(146): error C2614: 'CDUVariable': illegal member initialization: 'mValue' is not a base or member 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(165): error C2350: 'CDUVariable::Baud' is not a static member 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(165): note: see declaration of 'CDUVariable::Baud' 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(165): error C2248: 'CDUVariable::CDUVariable': cannot access private member declared in class 'CDUVariable' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(143): note: see declaration of 'CDUVariable::CDUVariable' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable' 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(166): error C2039: 'Firmware': is not a member of 'CDUVariable' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable' 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(166): error C2065: 'firmware': undeclared identifier 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(167): error C2039: 'Type': is not a member of 'CDUVariable' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable' 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(167): error C2065: 'type': undeclared identifier 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(168): error C2039: 'Serial': is not a member of 'CDUVariable' 
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable' 
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(168): error C2065: 'serial': undeclared identifier 
2>Generating Code... 
+0

你曾經想複製或分配CDUVariable嗎?什麼是典型的用例? (我懷疑,我們可能正在處理一個XY問題。) – Walter

+0

@Walter典型的用例是它對待這些枚舉類的類,比如它們的java等價物。我的想法是,我可以做像'auto cduVariable = CDUVariable(CDUVariable :: valueOf(static_cast (data))',我可以從原始數據查找枚舉值,也可以getStringVal併發送我嘗試將std :: string改爲const char *來解決非constexpr std :: string的問題,但是我無法得到僅用於編譯頭文件的版本 – johnco3

回答

1

我有一個類,我經常一個枚舉使用包裝,但是這需要一個cpp文件。誰能告訴我如何使用constexpr

爲了減少您的例子,一個最小的一個,考慮下面的類:

struct Example { 
    enum Value { A, B }; 
    static constexpr Example Foo{Value::A, "bar" }; 
    constexpr Example(Value v, std::string s): v{v}, s{s} {} 

private: 
    Value v; 
    std::string s; 
}; 

這或多或少是你的最後一次嘗試的簡化版本。能夠構建一個constexpr版本的Example到位需要
幾乎所有的作品,但一個事實,即:

  • static constexpr數據成員必須初始化,但Example是在點一個不完整的類型的報價爲Foo

  • 所有數據成員必須是(讓我說)constexpr constructible和std::string還沒有一個constexpr構造函數即可使用。

因此,您的嘗試將失敗,毫無疑問。另外,請注意,除非您正在使用C++ 17,否則您不能使用constexpr數據成員,或者您在.cpp文件中單獨定義它們,完全如您之前所做的那樣。那是因爲這些成員並沒有在C++ 11/14中被隱式定義。
這意味着你甚至不能在std::set::insert中使用它們,因爲它只接受引用。至少,除非你在.cpp文件中定義了一個定義,否則你不能使用它們。

所以,回到問題:

誰能告訴我怎麼constexpr

沒有用的,我們不能和它不值得。在我看來,你想要odr可用的數據成員,所以繼續static,並將定義放在專用文件中。

+0

感謝您的非常明確的解釋。 – johnco3

2

根據定義,枚舉值是恆定的,畢竟在運行時不能添加值。這就是爲什麼你不能枚舉聲明之前把constexpr一個原因,那將毫無意義,因爲它不會改變對enum事情:

constexpr enum Value { baud, firmware, type, serial }; 
^^^^^^^^^ 
illegal 

作爲一個側面說明,你不能構造一個constexprCDUVariable現在因爲它的構造函數不是constexpr。如果您嘗試正確標記它,它將失敗,因爲mStringVal沒有constexpr構造函數,並且每個變量都必須初始化。

如果只打算存儲單個字符,則可以在編譯時使用作爲基元的char

+1

_定義,enum是已經constexpr_ < - 這不是確切的,它引入了命名常量代替 – skypjack

+0

@skypjack嗯,是的,但那些命名常量是'constexpr',因爲它們在編譯時是固定的。因爲它對我來說很清楚,但我不是一個本地人 – Rakete1111

+0

它們比'constexpr'(語言定義它們的方式)的常量要多 – skypjack

1

你可以擺脫那些靜態變量有:

static const std::set<CDUVariable>& getValues() { 
    static const std::set<CDUVariable> gValues = { 
     { baud, "0"}, // or Baud(), 
     { firmware, "1"}, 
     { type, "2"}, 
     { serial, "3"} 
    }; 
    return gValues; 
} 

static const CDUVariable& Baud() { static const CDUVariable var{ baud, "0"}; return var; } 

static CDUVariable Baud() { return { baud, "0"}; }