#новичкам
memcpy — это один из самых быстрых способов скопировать данные и один из самых быстрых способов получить UB. Функция принимает
void* и size_t и радостно съест всё, что вы ей дадите: полиморфный тип, std::string, объект с нетривиальным деструктором. Компилятор не скажет ни слова, а программа сломается в самом неожиданном месте.В прошлых постах мы поговорили о трейтах. Для заданного типа они определяют, обладает ли тип определенным свойством или нет.
Давайте применим трейты на практике. Ограничим через них доступ к самописной обертке memcpy.
И в этом нам помогут концепты. Если трейты - это свойство типа, то концепт - это требование для типа.
Определим концепт, который требует, чтобы тип был объектом(не функцией и не ссылкой) и был тривиально копируемым:
template <typename T>
concept SafeForMemcpy = std::is_object_v<T> && std::is_trivially_copyable_v<T>;
И вот теперь мы говорим в шаблонном функции, что хотим потребовать от типа выполнения условия SafeForMemcpy. Это можно сделать разными способами, вот самый простой:
template <SafeForMemcpy T>
void safe_memcpy(T* dest, const T* src) {
static_assert(sizeof(T) > 0, "Cannot copy incomplete type");
std::memcpy(dest, src, sizeof(T));
}
Вместо ключевых слов
typename или class используется имя концепта. Теперь при использовании нетривиально копируемых типов будет появляться ошибка компиляции с нормальным сообщением о том, что тип не удовлетворяет концепту.
В будущих постах будет разбирать концепты чуть подробнее.
Require the best conditions. Stay cool.
#cpp20 #template