复杂的模板涉及constexpr以及更多
我试图在编写复杂的模板上变得更好。我选择了一个示例问题,其中我替换了std :: setw,std :: setfill和std :: hex,hex有些不同。 (注意:这个问题与iomanip无关。iomanip的内容只是一个示例问题。我的目标是学习一些模板的细微差别。)
因此,我的第一个目标是创建一个“ forsfortednumber”类,以包装整数,并随着模板参数的格式指令提供格式指令:
template<class VALUE, bool HEX, int WIDTH, char FILL>
class FormattedNumber {
public:
VALUE val_;
FormattedNumber(VALUE v) : val_(v) {}
};
template<class VALUE, bool HEX, int WIDTH, char FILL>
std::ostream &operator<<(std::ostream &oss, FormattedNumber<VALUE, HEX, WIDTH, FILL> n) {
if (HEX) oss << std::hex;
oss << std::setfill(FILL) << std::setw(WIDTH) << n.val_;
oss << std::dec << std::setfill(' ');
return oss;
}
效果很好。它使我可以写这样的代码:
std::cout << FormattedNumber<int, false, 0, ' '>(123); // '123'
std::cout << FormattedNumber<int, true, 4, '0'>(123); // '007b'
std::cout << FormattedNumber<int, false, 5, 'x'>(123); // 'xx123'
这是一个开始。接下来,第2步使其更易于使用。我想让用户写一些友好的东西,例如“ hex.width(10).fill('0')。make(123)”。我部分完成了这一点:
template<bool HEX, int WIDTH, char FILL>
class NumberFormat {
public:
constexpr static auto hex = NumberFormat<true, WIDTH, FILL>();
constexpr static auto dec = NumberFormat<false, WIDTH, FILL>();
constexpr static auto width5 = NumberFormat<HEX, 5, FILL>();
constexpr static auto width10 = NumberFormat<HEX, 10, FILL>();
constexpr static auto zfill = NumberFormat<HEX, WIDTH, '0'>();
constexpr static auto xfill = NumberFormat<HEX, WIDTH, 'x'>();
template<class VALUE>
static FormattedNumber<VALUE, HEX, WIDTH, FILL> make(VALUE v) {
return FormattedNumber<VALUE, HEX, WIDTH, FILL>(v);
}
};
constexpr auto hex = NumberFormat<true, 0, '0'>();
constexpr auto dec = NumberFormat<false, 0, '0'>();
这确实有效,它使我可以编写这样的代码:
std::cout << dec.width5.zfill.make(123); // '00123'
std::cout << dec.width10.xfill.make(123); // 'xxxxxxx123'
std::cout << hex.width5.xfill.make(123); // 'xxx7b'
这是朝着正确的方向朝着正确的方向迈出的一步,但是我希望能够以两种方式更改它。首先,我希望能够编写“宽度(10)”而不是“ width10”。 不幸的是,我尝试将其放入类NumberFormat:
constexpr static auto width(int n) {
return NumberFormat<HEX, ????, FILL>();
}
但是我无法弄清楚要把问号放在哪里。我当然可以这样做:
template<int N>
constexpr static auto width() {
return NumberFormat<HEX, N, FILL>();
}
但是,这要求用户写“ width&lt&gt;()”,这很丑陋。如果宽度的参数是整数字面的,则似乎这是可能的。
因此,我想改变的第二件事是我希望能够写“十六进制(123)”,而不是“ hex.make(123)”。 “ make”一词似乎是不必要的。我已经尝试将其添加到课堂上:
template<class VALUE>
constexpr static auto operator()(VALUE v) {
return FormattedNumber<VALUE, HEX, WIDTH, FILL>(v);
}
但是它不喜欢,显然Operator()需要非静态。我可以使其不静止,但是如果这样做,链接器会这样抱怨:
undefined reference to `NumberFormat<false, 10, (char)48>::zfill'
这很奇怪,那应该是静态的constexpr,即,只是一个常数,因此它不应该有任何链接。我不明白。
你们中的任何一个能解释一下是否有一种方法来执行“宽度”功能,并且您能解释一下为什么链接引起问题吗?有没有办法使我的“模板魔术”更好地工作?
I'm trying to get better at writing complicated templates. I've picked a sample problem in which I replace std::setw, std::setfill, and std::hex with something a little different. (Note: this question isn't about iomanip. The iomanip stuff is just a sample problem. My goal is to learn some of the nuances of templates.)
So my first goal was to create a 'FormattedNumber' class that wraps an integer, and also carries formatting directives along as template parameters:
template<class VALUE, bool HEX, int WIDTH, char FILL>
class FormattedNumber {
public:
VALUE val_;
FormattedNumber(VALUE v) : val_(v) {}
};
template<class VALUE, bool HEX, int WIDTH, char FILL>
std::ostream &operator<<(std::ostream &oss, FormattedNumber<VALUE, HEX, WIDTH, FILL> n) {
if (HEX) oss << std::hex;
oss << std::setfill(FILL) << std::setw(WIDTH) << n.val_;
oss << std::dec << std::setfill(' ');
return oss;
}
That works fine. It lets me write code like this:
std::cout << FormattedNumber<int, false, 0, ' '>(123); // '123'
std::cout << FormattedNumber<int, true, 4, '0'>(123); // '007b'
std::cout << FormattedNumber<int, false, 5, 'x'>(123); // 'xx123'
So that's a start. Next, step 2 was to make it easier to use. I wanted to let the user write something friendly, like "hex.width(10).fill('0').make(123)". I partially accomplished this:
template<bool HEX, int WIDTH, char FILL>
class NumberFormat {
public:
constexpr static auto hex = NumberFormat<true, WIDTH, FILL>();
constexpr static auto dec = NumberFormat<false, WIDTH, FILL>();
constexpr static auto width5 = NumberFormat<HEX, 5, FILL>();
constexpr static auto width10 = NumberFormat<HEX, 10, FILL>();
constexpr static auto zfill = NumberFormat<HEX, WIDTH, '0'>();
constexpr static auto xfill = NumberFormat<HEX, WIDTH, 'x'>();
template<class VALUE>
static FormattedNumber<VALUE, HEX, WIDTH, FILL> make(VALUE v) {
return FormattedNumber<VALUE, HEX, WIDTH, FILL>(v);
}
};
constexpr auto hex = NumberFormat<true, 0, '0'>();
constexpr auto dec = NumberFormat<false, 0, '0'>();
That does work, and it lets me write code like this:
std::cout << dec.width5.zfill.make(123); // '00123'
std::cout << dec.width10.xfill.make(123); // 'xxxxxxx123'
std::cout << hex.width5.xfill.make(123); // 'xxx7b'
That's another step in the right direction, but I'd like to be able to change that in two ways. First, I'd like to be able to write 'width(10)' instead of 'width10'.
Unfortunately, I've tried putting this into class NumberFormat:
constexpr static auto width(int n) {
return NumberFormat<HEX, ????, FILL>();
}
But I just can't figure out what to put where the question marks are. I could certainly do this instead:
template<int N>
constexpr static auto width() {
return NumberFormat<HEX, N, FILL>();
}
But that requires the user to write "width<5>()", which is ugly as heck. It seems like this should be possible, if the parameter to width is an integer literal.
So the second thing I'd like to change is I'd like to be able to write "hex(123)" instead of "hex.make(123)". The word "make" seems unnecessary. I've tried adding this to the class:
template<class VALUE>
constexpr static auto operator()(VALUE v) {
return FormattedNumber<VALUE, HEX, WIDTH, FILL>(v);
}
But it doesn't like that, apparently operator() needs to be non-static. I can make it non-static, but if I do that, the linker complains like this:
undefined reference to `NumberFormat<false, 10, (char)48>::zfill'
That's weird, that's supposed to be a static constexpr, ie, just a constant, so it shouldn't have any linkage. I don't understand this.
Can any of you explain if there's a way to do the 'width' function, and can you explain why that linkage is causing a problem? Is there a way to make my "template magic" work better?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论