如果您只是在寻找一个具体的例子,请考虑以下内容:
#include <cassert>
#include <type_traits>
#include <iostream>
namespace NS
{
enum direction { forward, backward, left, right };
struct vehicle { virtual ~vehicle() { } };
struct Car : vehicle
{
void MoveForward(int units) // (1)
{
std::cout << "in NS::Car::MoveForward(int)\n";
}
};
void MoveForward(Car& car_, int units)
{
std::cout << "in NS::MoveForward(Car&, int)\n";
}
}
template<typename V>
class HasMoveForwardMember // (2)
{
template<typename U, void(U::*)(int) = &U::MoveForward>
struct sfinae_impl { };
typedef char true_t;
struct false_t { true_t f[2]; };
static V* make();
template<typename U>
static true_t check(U*, sfinae_impl<U>* = 0);
static false_t check(...);
public:
static bool const value = sizeof(check(make())) == sizeof(true_t);
};
template<typename V, bool HasMember = HasMoveForwardMember<V>::value>
struct MoveForwardDispatcher // (3)
{
static void MoveForward(V& v_, int units) { v_.MoveForward(units); }
};
template<typename V>
struct MoveForwardDispatcher<V, false> // (3)
{
static void MoveForward(V& v_, int units) { NS::MoveForward(v_, units); }
};
template<typename V>
typename std::enable_if<std::is_base_of<NS::vehicle, V>::value>::type // (4)
mover(NS::direction d, V& v_)
{
switch (d)
{
case NS::forward:
MoveForwardDispatcher<V>::MoveForward(v_, 1); // (5)
break;
case NS::backward:
// ...
break;
case NS::left:
// ...
break;
case NS::right:
// ...
break;
default:
assert(false);
}
}
struct NonVehicleWithMoveForward { void MoveForward(int) { } }; // (6)
int main()
{
NS::Car v; // (7)
//NonVehicleWithMoveForward v; // (8)
mover(NS::forward, v);
}
HasMoveForwardMember
(2)void(V::*)(int)
是一个元函数,它使用给定类中的签名检查该名称的成员函数是否存在V
。MoveForwardDispatcher
(3)如果成员函数存在,则使用此信息调用成员函数,如果不存在,则回退到调用自由函数。mover
简单地将调用委托MoveForward
给MoveForwardDispatcher
(5)。
发布的代码将调用Car::MoveForward
(1),但如果此成员函数被删除、重命名或更改其签名,NS::MoveForward
则会改为调用。
另请注意,由于mover
是模板,因此必须进行 SFINAE 检查以保留仅允许从(4)NS::vehicle
中派生的对象传入的语义。为了证明,如果注释掉(7)和取消注释(8),将使用类型(6)的对象调用,尽管事实上.v_
mover
NonVehicleWithMoveForward
HasMoveForwardMember<NonVehicleWithMoveForward>::value == true
(注意:如果您的标准库不附带std::enable_if
and std::is_base_of
,请使用std::tr1::
orboost::
变体代替。)
通常使用这种代码的方式是始终调用自由函数,并以类似MoveForwardDispatcher
这样的方式实现自由函数,即自由函数只需调用传入的对象的成员函数(如果存在),而无需编写重载每个可能具有适当成员函数的类型的自由函数。