一个重要的问题是负载(payload)的差异在哪里,以及它们如何相同。在某些情况下,通过生产由负载确定类型的对象,然后通过通用于所有负载类型的虚拟接口与它们交互的系统是合理的。
另一种选择是假设您有一个有限且固定的负载类型列表,返回一个boost::variant相对容易。然后,调用一个接受变体中每种类型的函数对象的apply_visitor来处理它。
如果您只想以不同方式处理一种类型的负载,则编写“仅当类型匹配T时调用并运行lambda”的函数并不难。
因此,您可以获得以下语法:
struct State;
struct HandlePayload
{
typedef void return_type;
State* s;
HandlePayload(State* s_):s(s_) {}
void operator()( int const& payload ) const {
}
void operator()( std::shared_ptr<bob> const& payload ) const {
}
template<typename T>
void operator()( T const& payload ) const {
}
}
这很可爱,但你会注意到它相当间接。然而,你也会注意到可以编写带有通用类型 T 的模板代码来处理有效载荷,并针对某些情况使用诸如特征类的东西,或者使用显式特化。
如果您期望有效载荷是一种特定类型,并且只想在该情况下执行一些特殊工作,则在 boost::variant 上编写单一类型处理程序很容易。
template<typename T, typename Func>
struct Helper {
typedef bool return_type;
Func f;
Helper(Func f_):f(f_) {}
bool operator()(T const& t) {f(t); return true; }
template<typename U>
bool operator()(U const& u) { return false; }
};
template<typename T, typename Variant, typename Func>
bool ApplyFunc( Variant const& v, Func f )
{
return boost::apply_visitor( Helper<T, Func>(f), v );
}
这将在变量v上调用函数f,但仅在Variant中的类型T上调用,如果匹配成功则返回true。
使用此功能,您可以执行以下操作:
boost::variant<int, double> v = 1.0;
boost::variant<int, double> v2 = int(1);
ApplyFunc<double>( v, [&](double d) { std::cout << "Double is " << d << "\n"; } );
ApplyFunc<double>( v2, [&](double d) { std::cout << "code is not run\n"; } );
ApplyFunc<int>( v2, [&](int i) { std::cout << "code is run\n"; } );
或类似变体。
PayloadType()
返回什么? - David G