15

Я смотрю на этот исходный кодкодекс я никогда не видел в C++ 11

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'); 
}; 

Я запутался ..

+0

Да, извините за ошибку – Paul

+2

Взгляните на эти ссылки. Они должны все объяснить. - [Шаблоны Variadic] (http://www.cplusplus.com/articles/EhvU7k9E/) - [Пользовательские литералы] (http://en.cppreference.com/w/cpp/language/user_literal) - [Статические Утверждение] (http://en.cppreference.com/w/cpp/language/static_assert) –

ответ

22

Ваш код показывает три новые функции 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> 

Полный синтаксис шаблонов переменного числа битого изворотливый, Wikipedia имеет приличную статью о нем. Это особенно полезно для другой функции C++ 11: совершенная переадресация вариационного числа аргументов функции.

Экзотический вид int operator "" _b() определяет определяемый пользователем литерал, который позволяет добавлять собственные единицы к вашим типам и выражениям. Это просто означает, что целые числа, за которыми следуют _b, помечены определенной «единицей». См. Это question для более подробной информации. Одно практическое преимущество заключалось бы в том, чтобы избежать будущих сбоев приземления на Марсе (где СИ и имперские подразделения смешивались в своем программном обеспечении для посадки, без возможности компилятора его диагностировать).

static_assert выполняет то, что вы думаете, что он делает: он утверждает свое состояние статически, то есть на время компиляции. Когда утверждение не выполняется, компиляция прекращается. Это отличный способ обнаружить ошибки как можно скорее.

UPDATE

Специализация переменным числом шаблонов может быть очень удивительно, если у вас есть частично перекрывающиеся диапазоны аргументов: версия ноль или более аргументов соответствует только пустой список в вашем примере (в случае, если бы дали для нее определение).

#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.

Это, конечно, пример общего правила для частичной специализированности шаблонов, в котором указывается, что будет выбрана самая специализированная версия (одна или более более специализированная, чем нуль или больше, всегда можно использовать там, где первый может, но не наоборот). Но поскольку вариативные шаблоны часто не так «заметно» отличаются друг от друга, вы должны быть осторожны с их частичными специализациями.

1
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 meta-programming с использованием вариативных шаблонов.


Статические утверждения существуют, чтобы ограничить значения, которые могут принимать переменные-шаблоны.

 Смежные вопросы

  • Нет связанных вопросов^_^