解决方案 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:基于重载的技术
如果您正在使用 C++98 并且不想boost::enable_if
用作 的替代品std::enable_if
,则另一种方法包括利用重载决议和未使用的参数来区分辅助函数的两个重载。首先,您定义了两个虚拟类:
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; };
...
最后,您创建其中一种虚拟类型的实例,以选择辅助函数的适当重载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
{
...
}
};