我有以下标记调度代码(请参阅LiveWorkSpace)
#include <iostream>
// traits types
struct A {}; struct B {}; struct C {};
// helpers
void fun_impl(bool, A) { std::cout << "A\n"; }
void fun_impl(bool, B) { std::cout << "B\n"; }
// would like to eliminate this
void fun_impl(bool b, C)
{
if(b)
fun_impl(b, A());
else
fun_impl(b, B());
}
template<typename T>
void fun(bool b, T t)
{
// T = A, B, or C
fun_impl(b, t);
}
int main()
{
fun(true, A()); // "A"
fun(false, A()); // "A"
fun(true, B()); // "B"
fun(false, B()); // "B"
fun(true, C()); // "A"
fun(false, C()); // "B"
}
但是,此标记分派(dispatch)与函数
fun
紧密相关,我需要维护3个辅助函数来为使用此函数的每个函数实现此标记分派(dispatch)。参数推导失败:我试图将
fun_impl
抽象到mixed_dispatch
函数对象的模板参数中,但是如果我随后将fun_impl
作为参数传递,则不能推论应该需要2个重载中的哪一个。template<typename T>
struct mixed_dispatch
{
template<typename Fun>
void operator()(Fun f, bool b)
{
return f(b, T());
}
};
template<>
struct mixed_dispatch<C>
{
template<typename Fun>
void operator()(Fun f, bool b)
{
if (b)
return f(b, A());
else
return f(b, B());
}
};
template<typename T>
void fun(bool b, T)
{
// T = A, B, or C
mixed_dispatch<T>()(fun_impl, b); // ERROR: Fun cannot be deduced
}
问题:还有其他方法可以将标签分发与正在调用的函数分离开吗?
我愿意接受使用C++ 11可变参数模板/ Boost.Fusion或其他简化我当前代码的向导的任何建议(对于使用此特定调度的每个函数,我现在必须维护3个而不是2个辅助函数,以及更多复杂的分派(dispatch)助手功能的数量增长得更快)。
最佳答案
要选择一个重载函数,至少您必须告诉编译器目标函数的参数类型。因此我们可以将它们添加为模板类mixed_dispatch
的类型参数
template < typename Tag, typename... Args >
class mixed_dispatch {
std::function<void(Tag,Args...)> invoke;
public:
// for overloaded functions
mixed_dispatch( void(&f)(Tag,Args...) ) : invoke( f ) { }
// for function objects
template < typename F >
mixed_dispatch( F&& f ) : invoke( std::forward<F>(f) ) { }
void operator()( Args... args ) const {
invoke( Tag(), args... );
}
};
现在
mixed_dispatch
成为包装器,可以帮助您将Tag
对象传递给目标函数。如您所见,我们需要更改目标函数的签名(有点用)。void fun_impl(A1, bool) { std::cout << "A1\n"; }
在客户端代码中,例如
fun
:template< typename T >
void fun( bool b, T )
{
using dispatcher = mixed_dispatch<T,bool>;
dispatcher d = fun_impl;
d( b );
}