2017-07-21 46 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"}; }