Неявное преобразование может быть действительно полезным, если типы семантически эквивалентны. Например, представьте две библиотеки, которые реализуют тип одинаково, но в разных пространствах имен. Или просто тип, который в основном идентичен, за исключением некоторого семантического сахара здесь и там. Теперь вы не можете передать один тип в функцию (в одной из этих библиотек), которая была предназначена для использования другой, если эта функция не является шаблоном. Если это не так, вам нужно каким-то образом преобразовать один тип в другой. Это должно быть тривиальным (или иначе типы не так идентичны после всех!), Но вызов преобразования явно раздувает ваш код, в основном бессмысленные вызовы функций. Хотя такие функции преобразования могут фактически копировать некоторые значения вокруг, они практически ничего не делают с точки зрения "программистов" высокого уровня.
Неявные конструкторы преобразования и операторы, очевидно, могли бы помочь, но они вводят связь, так что один из этих типов должен знать о другом. Обычно, по крайней мере, при работе с библиотеками, это не так, потому что наличие одного из этих типов делает другой избыточным. Кроме того, вы не всегда можете изменять библиотеки.
Теперь я вижу два варианта того, как сделать неявное преобразование в пользовательском коде:
-
Первым будет предоставление прокси-типа, который реализует операторы преобразования и преобразования-конструкторы (и назначения) для всех задействованных типов и всегда их используют.
-
Второй требует минимального изменения в библиотеках, но обеспечивает большую гибкость: Добавьте конструктор преобразования для каждого задействованного типа, который может быть необязательно включен снаружи.
Например, для типа 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-рендеринг вектор).