Есть шаблон класса, который я бы не хотел использовать в своем проекте.
template<typename T, size_t Size>
class X {};
Я придумал следующую схему, чтобы сделать это.
Этап 1
Для следующего выпуска — скажем, версии «5» — я собираюсь предоставить «новый» класс с другим именем (замена) и преобразовать старый в устаревший псевдоним:
template<size_t ElementSize, size_t Size>
class X2 {};
template<typename T, size_t Size>
using X __attribute__ ((deprecated)) = X2<sizeof(T), Size>;
Это вызовет предупреждение для всех пользователей «старого» API, но код все равно будет работать.
Этап 2
В следующей версии — «6» — я собираюсь удалить «старый» устаревший класс, переименовать «новый» в старое имя и создать устаревший псевдоним:
template<size_t ElementSize, size_t Size>
class X {};
template<size_t ElementSize, size_t Size>
using X2 __attribute__ ((deprecated)) = X<ElementSize, Size>;
Это снова вызовет предупреждение для пользователей.
Этап 3
На этом последнем шаге, выполненном в версии «7», я удалю устаревший псевдоним, оставив только измененный класс.
template<size_t ElementSize, size_t Size>
class X {};
У всей этой схемы есть свои плюсы (на каждом этапе код компилируется и работает, для устаревшего интерфейса выдается только предупреждение) и минусы (пользователи вынуждены менять свой код дважды). Однако я не придумал ничего лучшего — все остальные варианты, которые я рассмотрел, в какой-то момент связаны с ошибкой компиляции. Основная проблема, с которой я здесь сталкиваюсь, заключается в том, что я хотел бы сохранить имя класса (на последнем этапе), но изменить шаблон «подпись» с <type, value>
в <value, value>
, что (как я предполагаю) исключает все другие умные варианты …
Есть ли лучший вариант? Если нет, то выглядит ли приведенная выше схема «приемлемой», или, может быть, мне следует просто вызвать одну ошибку компиляции и покончить с этим? Проект находится на ранней стадии разработки, поэтому меня не очень заботит обратная совместимость, но я подумал, что это очень хорошая возможность опробовать весь процесс.
Более простым решением может быть введение пары макросов.
На этапе 1 код, который определяет USE_NEW_API
Уже можно использовать новый API. На этапе 2 код, который определяет USE_OLD_API
все еще можно использовать старый API. На этапе 3 макросы игнорируются, и весь код должен использовать новый API.
Конечно, смешивать старый и новый API в одной программе немного сложнее, а смешивание их в одном модуле перевода требует решения проблем.
За кулисами, в фазе 1 у вас есть #if !(defined(USE_OLD_API) || defined(USE_NEW_API)) #define USE_OLD_API
на который вы переключаетесь #define USE_NEW_API
в фазе 2.
Других решений пока нет …