Условный типдеф в зависимости от "платформы"

Условный типдеф в зависимости от "платформы"
Условный типдеф в зависимости от "платформы" - victoriano @ Unsplash

Здесь у вас есть несколько вариантов, но серебряной пули нет.

Шаблонные/макроподобные подходы. Это то, что вы делаете со своими ifdefs. Дело в том, что ваш код не зависит от какого-либо конкретного поставщика для этого типа и компилируется только тогда, когда указан конкретный тип.

Использование шаблонов C++ на самом деле может быть предпочтительнее, чем препроцессор C, поскольку шаблоны могут упростить специализацию частей вашего кода для того или иного конкретного типа. Код для невыбранных типов можно отключить с помощью SFINAE.

Кроме того, вы можете абстрагироваться от разницы. Например, вы можете создать ByteArrayView, который может быть неявно сконструирован как из const QByteArray&, так и из const MyByteArray&, и внутренне делегировать этому источнику. Один из способов реализовать это для фиксированного числа типов — создать помеченное объединение указателей (например, std::variant<const QByteArray*, const MyByteArray*> или пару указателей, для которых вы гарантируете, что ровно один из них не равен нулю), но для этого потребуются предварительные объявления для тех типы. В качестве альтернативы вы можете использовать стирание типа на основе динамической диспетчеризации с классом шаблона, который создает оболочки для всех аргументов, подобных массиву байтов. Предшествующий уровень техники для этой стратегии std::function.

На практике эти подходы требуют большого количества шаблонов для небольшой ценности и значительно усложняют вашу кодовую базу, чтобы иметь дело с несколькими возможными типами. Часто предпочтительнее преобразовать в общее представление. Ваша программная система имеет компоненты с определенными границами. На этих границах преобразуйте представление данных в удобный для вас формат. Вы можете предоставить несколько потенциальных конверсий, которые вы можете защитить с помощью ifdef или шаблонов.

Здесь вам просто нужен массив байтов только для чтения. Классическое представление C для этого было бы:

void sumAllBytes(const char* bytes, size_t len);

API, ориентированный на итератор C++, будет принимать указатели начала/конца или, возможно, будет шаблонизирован по типу итератора:

void sumAllBytes(const char* begin, const char* end);


// or
template<class It>
void sumAllBytes(It begin, It end) { ... }

Решение C++20 вместо этого может использовать std::span или std::range.

Также может быть вполне разумно поддерживать только свой собственный тип MyByteArray. Если пользователь хочет QByteArray, ему придется конвертировать в ваш тип и из него. Хотя это может быть менее эффективным во время выполнения из-за необходимости копирования/распределения, большая простота полученного кода может стоить того — слишком умный код — это то место, где любят прятаться ошибки.

Рекомендую посмотреть эти видео для лучшего погружения в вопрос:

Прикрепленное видео 1 - Платформы RPA: как сделать правильный выбор

Прикрепленное видео 2 - Краш-тест платформы Visiology


LetsCodeIt, 19 января 2023 г., 06:02