暗黙的な変換は、型が意味的に同等である場合に非常に役立ちます。たとえば、同じ型を実装しているが名前空間が異なる 2 つのライブラリがあるとします。または、あちこちのセマンティックシュガーを除いて、ほとんど同じタイプです。関数がテンプレートでない限り、一方の型を他方を使用するように設計された (これらのライブラリの 1 つの) 関数に渡すことはできません。そうでない場合は、何らかの方法で一方の型を他方の型に変換する必要があります。これは些細なことであるはずです (そうでなければ、型は結局のところそれほど同一ではありません!) が、変換を明示的に呼び出すと、ほとんど意味のない関数呼び出しでコードが肥大化します。このような変換関数は実際にはいくつかの値をコピーする可能性がありますが、高レベルの「プログラマー」の観点からは本質的に何もしません。
暗黙の変換コンストラクターと演算子は明らかに役立つ可能性がありますが、それらはカップリングを導入するため、それらの型の 1 つが他の型について知る必要があります。通常、少なくともライブラリを扱う場合はそうではありません。これらのタイプの 1 つが存在すると、他のタイプが冗長になるためです。また、常にライブラリを変更できるとは限りません。
これで、ユーザー コードで暗黙的な変換を機能させる方法について 2 つのオプションが表示されます。
1 つ目は、関連するすべての型に対して変換演算子と変換コンストラクタ (および代入) を実装するプロキシ型を提供し、常にそれを使用することです。
2 つ目は、ライブラリに最小限の変更を加えるだけで済みますが、大きな柔軟性が得られます。外部からオプションで有効にできる、関連する型ごとに変換コンストラクターを追加します。
たとえば、型の場合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_ {};
デフォルトで暗黙的な変換を無効にします。
次に、2 つの型の間の変換を有効にするために、テンプレートを特殊化します。
template <> struct conversion_enabled<OtherA, A> : public boost::mpl::true_ {};
convert
ADL で見つけられる機能を実装します。
個人的には、強い反対意見がない限り、2 番目のバリアントを使用することを好みます。
実際の質問に移りましょう: 暗黙的な変換のために型を関連付ける好ましい方法は何ですか? 私の提案は良いアイデアですか?どちらのアプローチにも欠点はありますか? そのような変換を許可することは危険ですか? ライブラリの実装者は、一般に、使用されている可能性が最も高いソフトウェアで型が複製される可能性がある場合に 2 番目の方法を提供する必要があります (ここでは、これらのパッケージのほとんどが 3D を実装する 3D レンダリング ミドルウェアを考えています)。ベクター)。