假设我想编写一个通用类来维护一个始终保持在两个值之间的整数。像这样的东西:
template<int Lower, int Upper>
class MyInt {
private:
int m_int;
public:
// Constructors, operators...
};
类不变量是Lower <= m_int <= Upper
. 当然 MyInt 应该具有整数通常具有的所有常用操作,例如赋值和算术运算符。如果一个操作要让它处于破坏其不变量的状态,MyInt 会抛出。然而,在许多情况下,这应该是编译时可检测到的。考虑这个示例代码:
int foo = 500;
constexpr int const bar = 500;
MyInt<0,100> a = 15; // OK
MyInt<0,100> b = foo; // Throws at runtime
MyInt<0,100> c = 500; // Compile error?
MyInt<0,100> d = bar; // Compile error?
MyInt<0,100> f = std::integral_constant<int, 500>; // Compile error
对于std::integral_constant
,编写适当的构造函数是直截了当的。但是是否有可能编译时检测a
在范围内和c
不在d
范围内?分配的值要么是编译时已知的文字,要么是 constexpr 常量。
我已经尝试过 SFINAE-ing 等等,但我找不到从值语义到模板参数的方法,即使在这些情况下(我声称)这些值显然是编译时常量。
对于 C++17,该语言不提供实现此功能所需的工具是否属实?如果是,这是否会随着即将到来的 C++20 而改变?如果我正在寻找的东西是不可能的,这是什么原因?我的兴趣完全是教育性的,所以如果我遗漏了一些东西(比如文字实际上不是编译时常量或其他东西),我会很感兴趣。
注意:我知道f
通过引入自定义文字后缀并要求用户键入以下内容可以使大小写不那么难看:
MyInt<0,100> g = 15_constint; // OK
MyInt<0,100> h = 500_constint; // Compile error
我也知道提供这样的界面的可能性:
MyInt<0,100> i;
i.assign<500>(); // Compile error
然而,这两种变通方法都带有一定的输入开销,并且不一定是惯用的 C++。