解決策1:SFINAEベースの手法
このソリューションは、テンプレートのインスタンス化中にテンプレートパラメータの置換に失敗しても、コンパイルエラーが発生しないという事実に基づいています(置換の失敗はエラーではありません)。代わりに、そのテンプレートは過負荷の解決のために単に無視されます。したがって、いくつかのトリックを使用すると、インスタンス化時に提供されるテンプレート引数に応じて、特定の関数テンプレートのどのオーバーロードを表示するかを選択できます。
この手法を使用する場合、各過負荷の可視性を決定する識別条件が相互に排他的であることを確認することが重要です。そうしないと、あいまいさが生じる可能性があります。
まず、特定のクラスが葉であるかどうかを判断するのに役立ついくつかの特性メタ関数を定義する必要があります。
// Primary template
template<typename T> struct is_leaf<T> { static const bool value = false; };
// Specializations...
template<> struct is_leaf<Leaf1> { static const bool value = true; };
template<> struct is_leaf<Leaf2> { static const bool value = true; };
...
次に、std::enable_if
(またはboost::enable_if
C ++ 98を使用している場合)を使用して、呼び出し演算子のどのオーバーロードを表示するかを選択できます。
class NodeVisitor: public boost::static_visitor<void>
{
public:
// Based on the fact that boost::variant<> defines a type list called
// "types", but any other way of detecting whether we are dealing with
// a variant is OK
template<typename Node>
typename std::enable_if<
!is_same<typename Node::types, void>::value
>::type
operator()(const Node& e) const
{
boost::apply_visitor( *this, e );
}
// Based on the fact that leaf classes define a static constant value
// called "isLeaf", but any other way of detecting whether we are dealing
// with a leaf is OK
template<typename Leaf>
typename std::enable_if<is_leaf<Leaf>::value>::type
operator()(const Leaf& e) const
{
...
}
};
解決策2:過負荷ベースの手法
boost::enable_if
C ++ 98で作業していて、の代わりに使用したくない場合std::enable_if
、代替アプローチは、オーバーロード解決と、ヘルパー関数の2つのオーバーロードを区別するための未使用の引数を利用することです。まず、2つのダミークラスを定義します。
struct true_type { };
struct false_type { };
次に、is_leaf<>
メタ関数を再度作成し、リーフクラスに適切に特化します。
// Primary template
template<typename T> struct is_leaf<T> { typedef false_type type; };
// Specializations...
template<> struct is_leaf<Leaf1> { typedef true_type type; };
template<> struct is_leaf<Leaf2> { typedef true_type type; };
...
最後に、これらのダミー型の1つのインスタンスを作成して、ヘルパー関数の適切なオーバーロードを選択しますprocess()
。
class NodeVisitor: public boost::static_visitor<void>
{
public:
template<typename T>
void operator()(const T& e) const
{
typedef typename is_leaf<T>::type helper;
process(e, helper());
}
template<typename Node>
void process(const Node& e, false_type) const
{
boost::apply_visitor(*this, e);
}
template<typename Leaf>
void process(const Leaf& e, true_type) const
{
...
}
};