Нескучное программирование. Ограничения

Wait 5 sec.

В языке C++ перегрузки функций и шаблонов исторически были и остаются мощным инструментом для выражения различных реализаций одного и того же интерфейса. Многим перегрузки видятся как удобный способ дать одно имя разным функциям, но на практике понимание того, как компилятор выбирает нужную перегрузку, может стать источником ошибок и недоразумений. Компилятор же руководствуется сложным набором правил, которые мы ему предоставили, учитывает не только типы аргументов, но и порядок специализаций, преобразования типов, const-квалификаторы, шаблонные параметры и многое другое. А ошибки, возникающие при перегрузках, часто трудно диагностировать, поскольку сообщение компилятора может ссылаться на глубоко вложенные детали реализации вместо очевидного исходного кода. Об этом была предыдущая статья...С введением концептов и ограничений (requires) язык получил возможность управлять этой сложностью на уровне интерфейса. Вместо того чтобы надеяться на магию перегрузки и изощрённые трюки вроде SFINAE, мы теперь можем прямо выражать намерения: какие свойства должен иметь тип, чтобы функция или шаблон были корректны, что позволило перейти от «магии разрешения перегрузок» к декларативному описанию требований к типам.Давайте теперь поговорим о том, что именно делают ограничения (requires) в современном C++ и почему появление этого механизма стало таким важным шагом в развитии шаблоннов. Тут надо сделать немного шаг в сторону и вспомнить, что исторически шаблоны в C++ были мощным, но довольно опасным инструментом, еще одним языком в языке, на котором можно было сделать почти всё, было бы желание. В итоге компилятор позволял подставить или подхачить любой тип, а проверка того, «подходит ли он на самом деле», откладывалась до момента инстанцирования, что нередко приводило к ошибке далеко от места вызова, а сообщение о непосредственном месте ошибки превращалось в многостраничный отчёт о внутренней кухне компилятора и как он работает с шаблонами. requires меняют эту модель, позволяя описывать ожидания от типа явно и прямо в объявлении функции или класса. Читать далее