跟...共事std::bind
,我们需要以某种方式提供一定数量的占位符,具体取决于回调函数参数的数量。我已经描述了一种方法here https://stackoverflow.com/a/21193316/420683如何通过创建占位符生成器来做到这一点:
template<int> struct placeholder_template {};
通过部分专业化std::is_placeholder
对于上面的模板,std::bind
看到实例化placeholder_template<N>
作为占位符类型。使用通常的索引技巧,我们然后展开placeholder_template<0>{}, placeholder<1>{}, ...., placeholder<N-1>{}
, where N
是函数参数的数量。
template<typename... Params>
class callback_list
{
public:
using callback_t = std::function<void(Params...)>;
//Overload for non-member handlers:
void add( const callback_t& handler )
{
_handlers.push_back( handler );
}
private:
//Overload for member handlers:
template<typename CLASS, int... Is>
void add( CLASS& object_ref ,
void(CLASS::*member_function)( Params... ) ,
int_sequence<Is...> )
{
using namespace std::placeholders;
_handlers.push_back( std::bind( member_function ,
std::ref( object_ref ) ,
placeholder_template<Is>{}...
)
);
}
public:
template<typename CLASS>
void add( CLASS& object_ref ,
void(CLASS::*member_function)( Params... ) )
{
add( object_ref, member_function,
make_int_sequence<sizeof...(Params)>{} );
}
template<typename... ARGS>
void operator()( ARGS&&... args )
{
for( auto& handler : _handlers )
handler( std::forward<ARGS>( args )... );
}
private:
std::vector<callback_t> _handlers;
};
占位符生成器和整数序列的代码,来自另一个答案:
template<int...> struct int_sequence {};
template<int N, int... Is> struct make_int_sequence
: make_int_sequence<N-1, N-1, Is...> {};
template<int... Is> struct make_int_sequence<0, Is...>
: int_sequence<Is...> {};
template<int> // begin with 0 here!
struct placeholder_template
{};
#include <functional>
#include <type_traits>
namespace std
{
template<int N>
struct is_placeholder< placeholder_template<N> >
: integral_constant<int, N+1> // the one is important
{};
}
使用C++14,可以使用std::index_sequence_for<Params...>
而不是定制make_int_sequence<sizeof...(Params)>
.
旁注:如果您想接受带有 cv- 和 ref-限定符的成员函数,您可以使用非常通用的“模式”,例如
template<class C, class T>
void add(C& ref, T fun);
并通过 SFINAE 进行限制。这里有一个特点 http://coliru.stacked-crooked.com/a/00750bf7564ab6d4它可以让你从这样的函数指针中推断出参数的数量(通过tuple_size
).