【发布时间】:2019-02-15 11:13:42
【问题描述】:
我正在尝试在编译时制作一个与字符一起使用的模板。在这种情况下,我想施加一个约束,即必须始终存在给定字符数的精确倍数。
在没有完全匹配的情况下,我想在包的开头用 0 填充它们。
(顺便说一句,这背后的动机是想要(在编译时,作为更大问题的一部分)添加对将二进制和十六进制文字映射到std::array<unsigned char, N> 的支持,这很好用,除了填充那些不是字节的倍数)。
这是一个简化的示例,说明我正在尝试使填充起作用:
// Thingy operates on N*4 chars - if that's not met use inheritance to 0 pad until it is met.
template<char ...Args>
struct thingy : thingy<0, Args...> {
// All we do here is recursively add one more 0 via inheritance until the N*4 rule is met
};
// This specialisation does the real work, N=1 case only
template<char a, char b, char c, char d>
struct thingy<a,b,c,d> {
enum { value = (a << 24) | (b << 16) | (c << 8) | d };
};
// This handles chunking the N*4 things into N cases of work. Does work along the way, only allowed for exact N*4 after padding has happened.
template <char a, char b, char c, char d, char ...Args>
struct thingy<a,b,c,d,Args...> : thingy<a,b,c,d> {
static_assert(sizeof...(Args) % 4 == 0); // PROBLEM: this is a we're a better match than the template that pads things, how do we stop that?
// Do something with the value we just got and/or the tail as needed
typedef thingy<a,b,c,d> head;
typedef thingy<Args...> tail;
};
int main() {
thingy<1,1,1,1,1>(); // This should be equivalent to writing thingy<0,0,0,1,1,1,1,1>()
}
这击中了我的static_assert。问题是我们总是在这里匹配错误的专业化,这是我所期待的,因为它更专业化。
所以我环顾四周,发现了一些相同问题的例子for a function,但据我所知,这些都不适用于这里。
我尝试了更多的东西,但都没有达到我希望的效果,首先是天真的 enable_if sizeof...(Args) 正是我想要的:
template <char a, char b, char c, char d, typename std::enable_if<sizeof...(Args) % 4 == 0, char>::type ...Args>
struct thingy<a,b,c,d,Args...> : thingy<a,b,c,d> {
// ...
};
据我所知,这是不合法的,而且肯定不适用于我的编译器 - 在我们需要查询 sizeof...(Args) 的地方,Args 尚不存在。
据我所知,我们不能在包之后合法地添加另一个模板参数,这也失败了:
template <char a, char b, char c, char d, char ...Args, typename std::enable_if<sizeof...(Args) % 4 == 0, int>::type=0>
struct thingy<a,b,c,d,Args...> : thingy<a,b,c,d> {
// ...
};
出现错误:
pad_params_try3.cc:17:8: error: default template arguments may not be used in partial specializations
我还在继承本身中尝试了 SFINAE,但这似乎不是一个合法的地方:
template <char a, char b, char c, char d, char ...Args>
struct thingy<a,b,c,d,Args...> : std::enable_if<sizeof...(Args) % 4 == 0, thingy<a,b,c,d>>::type {
// ...
};
我们同时遇到了static_assert 和enable_if 中的错误。
pad_params_try4.cc:17:8: error: no type named 'type' in 'struct std::enable_if<false, thingy<'\001', '\001', '\001', '\001'> >'
struct thingy<a,b,c,d,Args...> : std::enable_if<sizeof...(Args) % 4 == 0, thingy<a,b,c,d>>::type {
^~~~~~~~~~~~~~~~~~~~~~~
pad_params_try4.cc:18:5: error: static assertion failed
static_assert(sizeof...(Args) % 4 == 0);
据我所知,通过阅读更多 this might even be considered a defect 可以看出,但这对我现在没有多大帮助。
如何使用 C++14、gcc 6.x 中的内容解决这个问题?有没有比完全回到绘图板更简单的选择?
【问题讨论】:
-
您可以使用一个辅助函数来解决此问题,该函数在实际打包之前使用您想要 SFINAE 的计算值调用。让我写一个答案。
标签: c++ c++14 template-meta-programming sfinae