c++ - 检测编译时文字和常量

标签 c++ templates c++17 generic-programming c++20

假设我想编写一个泛型类来维护一个始终介于两个值之间的整数。像这样:

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在范围内并且 cd不是吗?分配的值是编译时已知的文字或 constexpr 常量。

我试过 SFINAE 等等,但我找不到从值语义到模板参数的方法,即使对于(我声称)这些值显然是编译时常量的情况也是如此。

C++17 是否真的没有提供实现它所需的工具?如果是,这会随着即将到来的 C++20 而改变吗?如果我正在寻找的东西是不可能的,这是什么原因?我的兴趣完全是教育性的,所以如果我遗漏了什么(比如文字实际上不是编译时常量或其他东西),我会很感兴趣。

注意:我知道那个案例f可以通过引入自定义文字后缀并要求用户键入如下内容来变得不那么难看:

MyInt<0,100> g = 15_constint; // OK
MyInt<0,100> h = 500_constint; // Compile error

我也知道提供这样的接口(interface)的可能性:

MyInt<0,100> i;
i.assign<500>(); // Compile error

然而,这两种变通方法都会带来一定的输入开销,并且不一定是惯用的 C++。

最佳答案

In case what I'm looking for is impossible, what are the reasons for this?

基本上归结为 C++ 函数模型不允许函数识别 constexpr 参数和运行时参数之间的区别这一事实。如果函数采用 int,则它采用 int。该函数的行为不会因 int 是由常量表达式(如文字)还是运行时值提供而有所不同。

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

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

本质上,您想要的是函数可以声明参数为 constexpr(以及允许您拥有非 constexpr 版本的重载规则)。没有这样的提议被投票到 C++20 中。已经完成的最好的是 P1045 ,它甚至还没有被委员会讨论过,并且有一堆漏洞需要填补。所以我不会屏住呼吸。

关于c++ - 检测编译时文字和常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50667501/

相关文章:

c++ - 如何在另一个QVector <QVector <T> *>中动态存储QVector <T>的地址?

c++ - C++ 17 中的并行执行策略

c++ - 如何在qtcreator中实现Qabstractvideosurface和逐帧监控视频?

c++ - 模板化类如何解析在其类型之一上调用的重载非成员函数?

c++ - 如何正确地将参数包转发到 lambda 中?

c++ - 将 SFML 的 RenderWindow 对象传递给模板函数

c++17 - StateMachine 与 std::variant,正确进行自定义模板推导

c++ - boost 属性树 : Remove attribute from a node

c++ - 如何在C++中将字符串数组复制到动态数组

C++ typedef 与类冲突