Я пытаюсь сделать шаблон, который работает с символами, во время компиляции.В этом случае я хочу наложить ограничение на то, что всегда должно быть точное кратное определенному количеству символов.
В случае, когда нет точного соответствия, я хочу дополнить их 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
.Проблема в том, что мы всегда совпадаем с неверной специализацией, которую я ожидал, потому что она более специализированная.
Поэтому я оглянулся и нашел несколько примеров той же проблемы для функции , но, насколько я вижу, ни одно из них здесь не применимо.
Я попробовал еще несколько вещей, ни одна из которых не работала так, как я надеялся, сначала был наивно 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);
Насколько я могу судить по прочтению чуть больше , это даже можно считать дефектом , но это не сильно мне помогает прямо сейчас.
Как я могу обойти это, с тем, что у меня есть в C ++ 14, gcc 6.x?Есть ли более простой вариант, чем полностью вернуться к чертежной доске?