Привет, дорогой читатель, меня зовут Ксавье Жувено, и в этой статье мы поговорим о том, как проверять ограничения типов в C++. Этот пост был навеян правилом из первой главы Code Craft Пита Гудлиффа Защитное программирование.
Зачем проверять ограничения типов?
Давайте начнем с разговора о том, почему и когда мы должны проверять ограничение типа. Первый ответ, который приходит мне на ум, это потому что мы можем 😝
Но есть конкретное использование этого 😉
Самый распространенный, о котором я могу думать, это когда вы хотите преобразовать переменную из одного типа в другой. В большинстве случаев оба типа будут иметь разные ограничения, поэтому добавление утверждения, чтобы убедиться, что значение переменной правильно определено в целевом типе, может быть хорошей привычкой защитного программирования.
Другой случай, когда вы можете захотеть сделать это, — избежать неопределенного поведения или использовать в своих интересах определенное поведение переполнения для некоторых типов. Таким образом, вы можете захотеть избежать переполнения целочисленной переменной, если вы слишком сильно увеличиваете ее, поскольку это неопределенное поведение, но, с другой стороны, вы можете намеренно переполнить беззнаковую переменную следить за работой вашего процессора при выполнении встроенных программ.
Все эти случаи связаны с ограничениями типов. А если у вас есть другие примеры, с удовольствием прочту их в комментариях к этой статье 😄
Ограничения в стиле C: переменные препроцессора
Если у вас есть программа на C или на старом C++ (или даже на новом C++, плохо не отвечающем стандарту), вы могли столкнуться с той переменной препроцессора, которая хранит ограничения типов std.
Они выглядят как INT_MIN
и INT_MAX
для целочисленного типа или FLT_MIN
и FLT_MAX
для типа с плавающей запятой. Существуют также другие константы, такие как FLT_EPSILON
, которые представляют собой разницу между двумя числами с плавающей запятой.
Полный список вы можете найти здесь. Эти константы полезны, когда они нужны вам в интерфейсе C или при программировании на C, но если вы используете C++, я рекомендую вам использовать следующую технику 😉
Ограничения С++: std::numeric_limits
В стандартном C++ есть шаблон класса, который предоставляет ограничения и дополнительную информацию о типе числовых типов std. Этот класс называется numeric_limits
. При желании вы можете найти полную документацию здесь.
Его можно использовать следующим образом:
#include <limits>
constexpr auto int_upper_limit = std::numeric_limits::max();
У этого класса есть несколько преимуществ.
Прежде всего, он предоставляет вам единый интерфейс для ограничений всех типов, что означает, что его можно без проблем использовать внутри шаблона класса или функции, в то время как с решением в стиле C это будет намного сложнее.
#include <limits>
template <typename T> class MyClass { void someMethod() { constexpr auto variable = std::numeric_limits<T>::max(); // ... } };
Кроме того, синтаксис намного понятнее, чем решение в стиле C, и близок к английскому языку. 🤓
Наконец, его можно расширить на ваши собственные типы, чтобы все типы вашей программы могли использовать один и тот же интерфейс, и это то, что мы собираемся сделать сейчас. 😃
Создадим собственные ограничения типов
Как упоминалось в предыдущей части, огромным преимуществом std::numeric_limits
является то, что его можно использовать с вашими собственными типами, так что все типы вашей программы будут иметь одинаковый интерфейс при поиске ограничений на них. Вот как вы можете сделать это по максимуму:
#include <limits>
struct my_type;
template <> class std::numeric_limits { public: static constexpr int max() noexcept { return 1; } };
int main() { constexpr auto my_type_upper_limit = std::numeric_limits<my_type>::max(); static_assert(my_type_upper_limit == 1, "Error - the limit is not well set");
return 0; }
Давайте подробно рассмотрим, как работает этот пример. 🙂 Во-первых, мы указываем наш тип, названный здесь my_type
, чтобы можно было создать специализацию для шаблона класса std::numeric_limits
.
В специализации класса шаблона мы создаем метод max
, который следует сигнатуре, определенной стандартом. Вы можете, например, найти прототип метода max
здесь, а посмотреть другие методы, которые можно указать в std::numeric_limits
здесь.
Наконец, в функции main
мы вызываем метод max
, используя std::numeric_limits
с нашим собственным типом. И вуаля! Теперь у нас есть тип, который может использовать тот же интерфейс, что и стандартный для своих ограничений! 😄
Конечно, здесь мы указали только метод max
, но вам, вероятно, также потребуется указать методы min
и lowest
. Это можно сделать так же, как мы сделали для метода max
. 😉
Вывод
Я здесь не для того, чтобы начинать дискуссию о том, что лучше C или C++.
Если вы используете C, используйте способ C для проверки ограничений ваших типов. И если вы используете C++, то используйте для этого способ C++, это поможет вам поддерживать некоторую согласованность в том, как вы проверяете ограничения типов в своем коде.
Я хочу сказать, что если вы хотите интегрировать защитное программирование (а вы должны это сделать), вам нужно будет проверить ограничения вашего типа, и теперь вы знаете, как это сделать на C++. 😄
Спасибо всем за прочтение этой статьи, и до моей следующей статьи, хорошего дня 😉
Первоначально опубликовано на http://10xlearner.com 8 января 2020 г.