我有一个类,它将一个整数 Package 成一个只有编译器(和开发人员)知道的值范围,在运行时限制是未知的。类实现了操作符,这样限制就改变了,并返回一个新类型的新值,该值具有修改后的限制(这是至关重要的)。
下面的代码给出了类的一个例子,实现了+运算符(在c++20下编译):
#include <iostream>
using namespace std;
template< int LOWER_, int UPPER_ >
class MyRange final {
public:
constexpr static int LOWER = LOWER_;
constexpr static int UPPER = UPPER_;
template< int, int >
friend class MyRange;
constexpr MyRange(MyRange const &) noexcept = default;
constexpr MyRange(MyRange&&) noexcept = default;
constexpr ~MyRange() {}
template< int VALUE >
requires ( VALUE >= LOWER && VALUE <= UPPER )
static constexpr
MyRange wrap = MyRange( VALUE );
template< class _RHS, int _RHS_LOWER = _RHS::LOWER, int _RHS_UPPER = _RHS::UPPER,
int _RES_LOWER = LOWER + _RHS_LOWER, int _RES_UPPER = UPPER + _RHS_UPPER,
typename _RESULT_T = MyRange<_RES_LOWER, _RES_UPPER> >
friend
_RESULT_T
operator+(MyRange const lhs, _RHS const &rhs) noexcept {
int result = lhs.value + rhs.unwrap();
return construct<_RESULT_T>( result );
}
int unwrap() const noexcept { return value; }
private:
MyRange() = delete;
MyRange& operator=(MyRange const &) = delete;
MyRange& operator=(MyRange&&) = delete;
// this must not be exposed because value has to be checked against limits at compile-time;
// wrap<VALUE> is the public "constructor"
explicit constexpr MyRange(int value) noexcept : value(value) {}
// helper: construct another specialization of MyRange
template< class TO >
static constexpr TO construct(int value) noexcept { return TO(value); }
int const value;
};
字符串
如何使用:
int main() {
auto value = MyRange<5,20>::wrap<8>;
auto another = MyRange<6,10>::wrap<6>;
auto result = value + another;
// 14; limits: 11, 30
cout << result.unwrap() << "; limits: " << decltype(result)::LOWER << ", " << decltype(result)::UPPER << endl;
}
型
现在我有以下问题。我希望能够添加整数文字的范围类类型的变量。这可以通过显式或隐式转换来实现,但是这会使限制不必要地增加:
using Range = MyRange<5,20>;
auto value = Range::wrap<8>;
auto result = value + Range::wrap<6>;
// 14; limits: 10, 40
cout << result.unwrap() << "; limits: " << decltype(result)::LOWER << ", " << decltype(result)::UPPER << endl;
型
当然,我可以显式地 Package 字面整数以获得所需的结果:
auto value = MyRange<5,20>::wrap<8>;
auto result = value + MyRange<6,6>::wrap<6>;
// 14; limits: 11, 26
cout << result.unwrap() << "; limits: " << decltype(result)::LOWER << ", " << decltype(result)::UPPER << endl;
型
但我不喜欢。用户端开销太大。我更喜欢写类似auto result = value + 6;
的东西,整数文字6
在传递给运算符之前隐式转换为MyRange<6,6>::wrap<6>
。
这在编译时可能吗?
我已经尝试过使用一个consteval函数,它带有一个值参数,用于创建所需的MyRange类型,但不幸的是,consteval函数的参数不是constexpr,尽管该函数保证在编译时执行。我所需要的只是从公式(编译时已知)中隐式地获取整数字面量,以创建使用字面量值作为模板参数的所需类型。
2条答案
按热度按时间jfgube3f1#
否:表达式的类型不能依赖于其中的文字值(在任何模板参数或数组边界之外,
0
可能是指针的特殊例外)。这是“constexpr
函数参数”问题的重演:也许有一天但不是现在q43xntqr2#
如果不介意多输入两个字符,可以使用数字文字运算符模板:
字符串
这里,
digit
表示数字的指数,因此对于个位数,digit
为0,对于十位数,digit
为1,依此类推。但是,数字文本运算符模板不适用于负数,因此要支持它,需要为
MyRange
添加一元减号运算符的重载。Edit:通过使用递归,不需要将
""_r
作为模板就可以做到这一点。