检测编译时文字和常量

Dra*_*-On 8 c++ templates generic-programming c++17 c++20

假设我想编写一个通用类,它维护一个始终保持在两个值之间的整数.像这样的东西:

template<int Lower, int Upper>
class MyInt {
    private:
        int m_int;
    public:
        // Constructors, operators...
};
Run Code Online (Sandbox Code Playgroud)

类不变量就是这样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
Run Code Online (Sandbox Code Playgroud)

因为std::integral_constant,编写适当的构造函数是直截了当的.但是,它可能编译时,检测a距离范围,c以及d有没有关系?指定的值是编译时已知的文字或constexpr常量.

我已经尝试了SFINAE-ing around和whatnot,但我找不到从值语义到模板参数的方法,即使对于这些情况,我声称这些值显然是编译时常量.

对于C++ 17来说,语言是否真的没有提供实现它所需的工具?如果是的话,即将推出的C++ 20会改变吗?如果我正在寻找的是不可能的,这是什么原因?我的兴趣完全是教育性的,所以如果我遗漏某些东西(比如文字实际上不是编译时常量或其他东西),我会感兴趣.

注意:我知道f通过引入自定义文字后缀并要求用户输入如下内容,可以减少案例:

MyInt<0,100> g = 15_constint; // OK
MyInt<0,100> h = 500_constint; // Compile error
Run Code Online (Sandbox Code Playgroud)

我也知道有可能提供这样的界面:

MyInt<0,100> i;
i.assign<500>(); // Compile error
Run Code Online (Sandbox Code Playgroud)

然而,这两种解决方法都带有一定的打字开销,并不一定是惯用的C++.

Nic*_*las 9

如果我正在寻找的是不可能的,这是什么原因?

基本上,它归结为C++函数模型不允许函数识别constexpr参数和运行时参数之间的区别这一事实.如果一个函数需要一个int,那么它需要一个int.根据int是由常量表达式(如文字)还是运行时值提供,该函数的行为不能有所不同.

即使是constexpr 功能,这也是如此.您不能拥有constexpr可以对其参数进行编译时检查的函数.评估可以在编译时完成,但foo(500);最终的行为必须与执行相同auto b = 500; foo(b);.

这就是为什么变通方法都涉及使用技巧将常量表达式放在模板参数中,这种识别是可能的.当然,模板参数永远不能是运行时值,因此会产生其他问题(例如必须具有多个函数).作为一个模板参数是一个通常很痛苦的事情.

基本上,你想要的是一个函数可以声明一个参数constexpr(以及重载规则,以允许你有一个非constexpr版本).没有这样的提案被投票到C++ 20中.最好的是P1045,委员会尚未讨论过,并且还有一堆需要填补的漏洞.所以我不会屏住呼吸.

  • 我不同意`constexpr`函数不能进行编译时间检查.看看我的答案,更一般地说是关于constexpr函数抛出的意思 (2认同)

bar*_*top 6

试试这个吧.这个例子非常简单:

template<int Max, int Min>
class MyInt
{
public:
    constexpr MyInt(int i) : m_int(i > Max ? throw std::exception("out of bouonds int") : ( i < Min ? throw std::exception("out of bouonds int") : i)) {}
private:
    int m_int;
};


int main()
{
    MyInt<1, 2> i(4);
}
Run Code Online (Sandbox Code Playgroud)

它显示编译时错误:).我使用这个SO问题作为指导: constexpr构造函数与编译时验证