C++ C++;使用允许的值定义类型

C++ C++;使用允许的值定义类型,c++,C++,我正在编写一个简单的类来设置AVR微控制器上的串行端口。 有些参数只有几个有意义的值,例如波特率、奇偶校验类型或停止位数。我想创建一个类型,一个整数的子集,可以是1或2。我可以创建枚举类型: enum stopBits { one, two }; 我不喜欢这个解决方案(拼写波特率值?)。 我提出了以下建议: template<int vv> struct stopBits { static_assert( vv == 1 || vv == 2, "stop bit valu

我正在编写一个简单的类来设置AVR微控制器上的串行端口。 有些参数只有几个有意义的值,例如波特率、奇偶校验类型或停止位数。我想创建一个类型,一个整数的子集,可以是1或2。我可以创建枚举类型:

enum stopBits { one, two };
我不喜欢这个解决方案(拼写波特率值?)。 我提出了以下建议:

template<int vv> struct stopBits {
    static_assert( vv == 1 || vv == 2, "stop bit values can be 1 or 2");
    int value = vv;
};
// usage:
stopBits<2> s;
这样,我就可以编写一个类,其中包含以下内容:

serial::serial(baudRate b, stopBits s = 1, parity p = none);
在寻找解决方案时,我发现自己陷入了一个兔子洞:模板参数推导、有界::整数库、不能为constexpr的函数参数,以及。
这是可以做到的,还是最好投降继续前进?提前感谢大家。

您可以进行运行时或编译时检查,但不能同时进行

如果您有编译时检查,您将被迫以某种方式硬编码这些值。这是constexpr和static_断言的域。这是您的第一个解决方案

如果要将值传递给构造函数,则会丢失编译时验证,因为现在正在赋值,而编译器不知道可以传递给构造函数的值是什么。您可以使用诸如bounded::integer或roll之类的工具在运行时检查值并相应地进行操作。(例如运行时错误)


您需要问自己什么是代码的不可变属性。如果它是不可变的(对于这个用例),您应该使用模板参数。如果这个实例是不可变的,但在一个用例中可能会有所不同,那么应该使用常量成员变量

您的解决方案的问题是
停止位
停止位
是不同的类型,这使得在运行时很难决定要使用哪种类型

您可以对具有私有构造函数的非模板类和返回该类对象的友元或静态“make”函数模板执行类似的操作。类似这样的内容(警告,未测试的代码):

类波特率{
私人:
波特率(整数bps):bps(bps){}
公众:
模板静态constexpr波特率make(){
静态断言(无论什么);
返回波特率(bps);
}
常量int bps;
};
自动r=慢?波特率::make():波特率::make();

如果您不喜欢语法,可以通过创建两级类层次结构并将静态检查移动到那里来实现无缝连接,但这只是语法上的甜点。

枚举名称中的第一个符号必须是字母,因此您可以将
停止位定义为
SB1
SB2
,或者类似的内容。根据您目前掌握的知识,避免“分析瘫痪”,使用最简单的解决方案。一旦您对问题有了更好的了解,请更改解决方案。如果有效值是连续的,您可以使用中的一个答案来限制数字类型的范围。另外,请小心使用模板解决方案,因为停止位和停止位是不同的类型,因此您将无法将其传递给serial::serial(…)没有serial::serial本身接受模板参数。我完全可以同时进行运行时和编译时检查,如果每次都检查不同的内容,这甚至可能有意义。我喜欢这个解决方案。。。语法糖版本是如何制作的?我做得不对,我从一个子类构造函数中调用make():baudChild(int-bps),但是bps现在不是constexpr。我试过了,但效果不太好。结果是
条件?baudRate():baudRate()
无效,即使这两个专业都来自同一个基类。所以忽略这一点。
serial::serial(baudRate b, stopBits s = 1, parity p = none);
class baudRate { 
   private:
     baudRate(int bps) : bps(bps) {}   
   public:
     template <int bps_> static constexpr baudRate make() {
       static_assert(whatever);
       return baudRate(bps_);
     }
   const int bps;
};

auto r = slow ? baudRate::make<9600>() : baudRate::make<115200>();