Неявное преобразование может быть действительно полезным, когда типы семантически эквивалентны. Например, представьте две библиотеки, которые идентично реализуют тип, но в разных пространствах имен. Или просто тип, который в основном идентичен, за исключением некоторого семантического сахара здесь и там. Теперь вы не можете передать один тип в функцию (в одной из этих библиотек), которая была разработана для использования другого, если эта функция не является шаблоном. Если это не так, вам нужно как-то преобразовать один тип в другой. Это должно быть тривиально (иначе все-таки типы не так уж идентичны! ), но вызов преобразования явно раздувает ваш код в основном бессмысленными вызовами функций. Хотя такие функции преобразования могут фактически копировать некоторые значения, они по существу ничего не делают с точки зрения высокоуровневых «программистов».
Неявные конструкторы и операторы преобразования, очевидно, могут помочь, но они вводят связь, так что один из эти типы должны знать о другом. Обычно, по крайней мере, при работе с библиотеками, это не так, потому что наличие одного из этих типов делает другой излишним. Кроме того, вы не всегда можете изменять библиотеки.
Теперь я вижу два варианта того, как заставить работать неявное преобразование в пользовательском коде:
Первый - предоставить прокси-тип, который реализует операторы преобразования и преобразование- конструкторы (и присваивания) для всех задействованных типов и всегда их используют. Добавьте конструктор преобразования для каждого задействованного типа, который может быть дополнительно включен извне.
Например, для типа A
добавьте конструктор:
template <class T> A(
const T& src,
typename boost::enable_if<conversion_enabled<T,A>>::type* ignore=0
)
{
*this = convert(src);
}
и шаблон
template <class X, class Y>
struct conversion_enabled : public boost::mpl::false_ {};
, который отключает неявное преобразование по умолчанию.
Затем, чтобы включить преобразование между двумя типами, настройте шаблон:
template <> struct conversion_enabled<OtherA, A> : public boost::mpl::true_ {};
и реализуйте функцию convert
, которую можно найти через ADL.
Я лично предпочел бы использовать второй вариант, если против него нет веских аргументов.
Теперь перейдем к собственно вопросу (ам): Какой предпочтительный способ ассоциировать типы для неявного преобразования? Мои предложения хорошие идеи? Есть ли недостатки у любого подхода? Опасно ли разрешать подобные преобразования? Должны ли разработчики библиотеки в целом предоставлять второй метод, когда он Скорее всего, их тип будет воспроизведен в программном обеспечении, с которым они, скорее всего, будут использоваться (здесь я имею в виду промежуточное ПО для 3D-рендеринга, где большинство этих пакетов реализуют 3D-вектор).