Я смотрю на этот исходный код
template<char... digits>
struct conv2bin;
template<char high, char... digits>
struct conv2bin<high, digits...> {
static_assert(high == '0' || high == '1', "no bin num!");
static int const value = (high - '0') * (1 << sizeof...(digits)) +
conv2bin<digits...>::value;
};
template<char high>
struct conv2bin<high> {
static_assert(high == '0' || high == '1', "no bin num!");
static int const value = (high - '0');
};
template<char... digits>
constexpr int operator "" _b() {
return conv2bin<digits...>::value;
}
int array[1010_b];
и мне интересно, если это действительно C ++.
template<char high, char... digits>
struct conv2bin<high, digits...> {
Что это? Шаблонная специализация, которая не специализируется?
И почему в объявлении структуры есть строки кода, например
struct conv2bin<high> {
static_assert(high == '0' || high == '1', "no bin num!");
static int const value = (high - '0');
};
Я не совсем понимаю..
Ваш код показывает три новых функции C ++ 11: вариационные шаблоны, пользовательские литералы а также статические утверждения.
Общий шаблон класса variadic задает ноль или более аргументов, специализированные версии — один или несколько, и ровно один, соответственно.
// digits can be the empty set, so 0 or more arguments
template<char... digits>
struct conv2bin;
// digits can be the empty set, so 1 or more arguments
template<char high, char... digits>
struct conv2bin<high, digits...>
// fully specialized for 1 argument
template<char high>
struct conv2bin<high>
Полный синтаксис шаблонов с вариациями немного странный, Википедия есть достойная статья об этом. Это особенно полезно для другой функции C ++ 11: идеальная пересылка переменного числа аргументов функции.
Экзотический вид int operator "" _b()
определяет пользовательский литерал, который является способом добавления ваших собственных модулей в ваши типы и выражения. Это просто означает, что целые числа, сопровождаемые _b
помечены определенным «блоком». Видеть это вопрос Больше подробностей. Одним из практических преимуществ было бы предотвращение будущих сбоев Марс-Лэндер (где СИ и имперские единицы смешивались в их программном обеспечении посадки, без компилятора, способного его диагностировать).
static_assert
делает именно то, что, как вы думаете, он делает: он утверждает свое состояние статически, то есть в время компиляции. Когда утверждение не выполняется, компиляция останавливается. Это отличный способ обнаружить ошибки как можно скорее.
ОБНОВИТЬ
Специализация шаблонов variadic может быть очень удивительной, когда у вас есть частично перекрывающиеся диапазоны аргументов: версия с нулевым или большим количеством аргументов будет соответствовать только пустому списку в вашем примере (в случае, если вы предоставили определение для него).
#include <iostream>
template<int... Args>
struct Test
{
enum { value = 0 };
};
template<int I, int... Args>
struct Test<I, Args...>
{
enum { value = 2 };
};
template<int I>
struct Test<I>
{
enum { value = 1 };
};
int main()
{
std::cout << Test<>::value << "\n"; // matches zero or more version
std::cout << Test<0>::value << "\n"; // matches single argument version
std::cout << Test<0, 0>::value << "\n"; // matches one or more version, not the zero or more one!
}
Выход на LiveWorkSpace.
Это, конечно, пример общего правила частичной специализации шаблона, которое гласит, что самая специализированная версия будет выбран (один или более более специализирован, чем ноль или более, поскольку последний всегда можно использовать там, где первый может, но не наоборот). Но поскольку вариационные шаблоны часто не так «заметно» отличаются друг от друга, вам следует быть особенно осторожными с их частичной специализацией.
template<char... digits>
struct conv2bin;
Это шаблон форвардной декларации. Он не должен быть полностью определен, потому что, если он используется неподдерживаемым образом, вы обнаружите ошибку раньше (компиляция не удастся). Этот конкретный пример не приведет к сбою компиляции, поскольку специализации охватывают все возможные случаи.
template<char high, char... digits>
struct conv2bin<high, digits...> {
static_assert(high == '0' || high == '1', "no bin num!");
static int const value = (high - '0') * (1 << sizeof...(digits)) +
conv2bin<digits...>::value;
};
Это частичная специализация, где устанавливается одно значение шаблона. Остальные просто перенаправляются на «нижний уровень» типа шаблона. Эта структура шаблона полностью определена и содержит переменную-член типа int, значение которой зависит от значения ‘high’ и следующего шаблона.
template<char high>
struct conv2bin<high> {
static_assert(high == '0' || high == '1', "no bin num!");
static int const value = (high - '0');
};
Опять частичная специализация шаблона, определяющая значение, когда параметры шаблона содержат только один параметр в своем списке.
Итак, в целом это шаблонное метапрограммирование используя вариадические шаблоны.
Статические утверждения предназначены для ограничения значений, которые могут принимать переменные шаблона.