在阅读了这个question的答案后,我了解到SFINAE可以用于根据类是否具有特定的成员函数来在两个函数之间进行选择。它等同于下面的语句,只是if语句中的每个分支都被分成一个重载函数:
template<typename T>
void Func(T& arg)
{
if(HAS_MEMBER_FUNCTION_X(T))
arg.X();
else
//Do something else because T doesn't have X()
}变成了
template<typename T>
void Func(T &arg, int_to_type<true>); //T has X()
template<typename T>
void Func(T &arg, int_to_type<false>); //T does not have X()我想知道是否有可能扩展SFINAE来执行多个规则。等同于这个的东西:
template<typename T>
void Func(T& arg)
{
if(HAS_MEMBER_FUNCTION_X(T)) //See if T has a member function X
arg.X();
else if(POINTER_DERIVED_FROM_CLASS_A(T)) //See if T is a pointer to a class derived from class A
arg->A_Function();
else if(DERIVED_FROM_CLASS_B(T)) //See if T derives from class B
arg.B_Function();
else if(IS_TEMPLATE_CLASS_C(T)) //See if T is class C<U> where U could be anything
arg.C_Function();
else if(IS_POD(T)) //See if T is a POD type
//Do something with a POD type
else
//Do something else because none of the above rules apply
}这样的事情有可能发生吗?
谢谢。
发布于 2010-04-27 10:44:18
这当然是可能的;您只需小心地确保所有分支都是互斥的,否则您将以模棱两可告终。
看看Boost Type Traits和Boost Enable If,这是支持这一点的两个最好的工具。Boost ICE (代表整型常量表达式)可用于组合多个类型特征,以帮助您进行更复杂的类型匹配(并确保您的重载是互斥的。
这可能有点复杂和令人费解,所以这里有一个相对简单的示例。假设你有一个类层次结构:
struct Base { };
struct Derived : Base { };并且您希望为Base调用函数foo的一个重载,并为从Base派生的任何类调用另一个重载。第一次尝试可能如下所示:
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
using namespace boost;
using namespace boost::type_traits;
template <typename T>
typename enable_if<is_same<Base, T>, void>::type
foo(const T&) { }
template <typename T>
typename enable_if<is_base_of<Base, T>, void>::type
foo(const T&) { } 但是,如果T是基类,则is_base_of返回true,因此如果您尝试调用foo(Base()),则会有歧义,因为两个函数模板都匹配。我们可以通过组合使用类型特征和Boost ICE辅助对象来解决这个问题:
template <typename T>
typename enable_if<is_same<Base, T>, void>::type
foo(const T&) { }
template <typename T>
typename enable_if<
ice_and<
is_base_of<Base, T>::value,
ice_not<is_same<Base, T>::value>::value
>, void>::type
foo(const T&) { }这些重载是相互排斥的,它们确保了没有歧义。
您的一些示例不受支持(即HAS_MEMBER_FUNCTION_X;我对IS_TEMPLATE_CLASS_C不太确定--取决于您想用它做什么,您也许能够使某些东西工作),但一般来说,这是可能的。
发布于 2010-04-27 10:45:33
你实现它的方式,不是。如果arg没有其中一个函数,编译将会失败。(我认为您知道这一点,只是为了确保)。
但是,可以使用模板专门化(隐藏在boost mpl的魔力中)来做到这一点。
有时,您可以使用带有元函数的boost vector来完成此操作:请查看http://www.boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual.html
typedefs typename mpl::vector<f0,f1,...>::type handlers; // different handlers
// convert logic to int N to map condition to handler
// can use ternary or bit shift trick
// more general approach could be to use vector of mpl::bool_ and mpl::find
typedef typename mpl::vector_c<bool, (first_condition),
(second_condition),...>::type condition;
typedef typename mpl::find<condition, mpl:: bool_<true> >::type iterator;
typedef typename mpl::at<handlers, iterator::pos::value>::type handler;
handler::apply(...); // call handler with some arguments根据具体的需求,您可以尝试不同的方法。上面是几个小时前做的事情
发布于 2010-04-27 17:34:46
当你意识到这一点时,问题就简单了。
if (a) { X(); }
else if (b) { Y(); }的意思完全相同
if (a) { X(); }
if (!a && b) { Y(); }但是,您也可以扩展您的true/false二分法。
enum FuncVariants { HasMember, PointerDerivedFromA, DerivedFromB, InstanceOfC, isPod }
template<typename T>
void Func(T &arg, int_to_type<HasMember>);
template<typename T>
void Func(T &arg, int_to_type<DerivedFromA>);
template<typename T>
void Func(T &arg, int_to_type<DerivedFromB>);
template<typename T>
void Func(T &arg, int_to_type<InstanceOfC>);(显然,当调用时,您必须小心,因为选项不是相互排斥的)
https://stackoverflow.com/questions/2718386
复制相似问题