Loosely coupled implicit conversion
- by ltjax
Implicit conversion can be really useful when types are semantically equivalent. For example, imagine two libraries that implement a type identically, but in different namespaces. Or just a type that is mostly identical, except for some semantic-sugar here and there. Now you cannot pass one type into a function (in one of those libraries) that was designed to use the other, unless that function is a template. If it's not, you have to somehow convert one type into the other. This should be trivial (or otherwise the types are not so identical after-all!) but calling the conversion explicitly bloats your code with mostly meaningless function-calls. While such conversion functions might actually copy some values around, they essentially do nothing from a high-level "programmers" point-of-view.
Implicit conversion constructors and operators could obviously help, but they introduce coupling, so that one of those types has to know about the other. Usually, at least when dealing with libraries, that is not the case, because the presence of one of those types makes the other one redundant. Also, you cannot always change libraries.
Now I see two options on how to make implicit conversion work in user-code:
The first would be to provide a proxy-type, that implements conversion-operators and conversion-constructors (and assignments) for all the involved types, and always use that.
The second requires a minimal change to the libraries, but allows great flexibility:
Add a conversion-constructor for each involved type that can be externally optionally enabled.
For example, for a type A add a constructor:
template <class T> A(
const T& src,
typename boost::enable_if<conversion_enabled<T,A>>::type* ignore=0
)
{
*this = convert(src);
}
and a template
template <class X, class Y>
struct conversion_enabled : public boost::mpl::false_ {};
that disables the implicit conversion by default.
Then to enable conversion between two types, specialize the template:
template <> struct conversion_enabled<OtherA, A> : public boost::mpl::true_ {};
and implement a convert function that can be found through ADL.
I would personally prefer to use the second variant, unless there are strong arguments against it.
Now to the actual question(s): What's the preferred way to associate types for implicit conversion? Are my suggestions good ideas? Are there any downsides to either approach? Is allowing conversions like that dangerous? Should library implementers in-general supply the second method when it's likely that their type will be replicated in software they are most likely beeing used with (I'm thinking of 3d-rendering middle-ware here, where most of those packages implement a 3D vector).