我试图为列表操作编写通用方法锁定包装。我目前拥有的是:
template <typename OP, typename... ARGS>
auto locked_call (OP op, ARGS... args) const
-> decltype(op(args...)) {
std::lock_guard<std::mutex> g(lock_);
return op(args...);
}
而且,我可以这样使用它:
auto push_back = [this](decltype(p) p) {
return list_.push_back(p); };
locked_call(push_back, p);
但是,我希望能够将要直接调用的方法传递到locked_call
中,并直接针对list_
进行调度。
template <typename METHOD, typename... ARGS>
auto locked_call (METHOD op, ARGS... args) const
-> decltype((list_.*op)(args...)) {
std::lock_guard<std::mutex> g(lock_);
return (list_.*op)(args...);
}
我很快意识到,由于方法重载,这很棘手,研究似乎表明明确解决重载是必需的。
locked_call(static_cast<void (List::*)(const int &)>(&List::push_back), p);
模板或decltype
是否可以巧妙地使用,以允许代码将方法名称简单地传递到locked_call
中?
作为一种技巧,我可以使用宏通过自动生成lambda来实现简化的语法:
#define LOCKED_CALL(METHOD, ...) \
locked_call([this,##__VA_ARGS__](){ \
return list_.METHOD(__VA_ARGS__); })
但是我希望有一个等效的模板。
答案 0 :(得分:3)
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
->decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
#define METHOD(...) \
[](auto&& self, auto&&...args) \
RETURNS((decltype(self)(self).* __VA_ARGS__)( decltype(args)(args)... ) )
然后我们可以做:
locked_call(METHOD(&List::push_back), list, p);
它应该可以工作。
这需要c++14支持。
或者:
#define OVERLOADS_OF(...) \
[&](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
会让你做
locked_call(OVERLOADS_OF(list.push_back), p);
答案 1 :(得分:1)
您必须明确说明要使用的重载。
您可以将static_cast
替换为模板参数:
template <typename R, typename... ARGS>
R locked_call (R (List::*op)(ARGS...), ARGS... args) const {
std::lock_guard<Mutex> g(lock_);
return (list_.*op)(args...);
}
void add (int p) {
locked_call<void, const int &>(&List::push_back, p);
}
或者,您可以简单地使用局部变量来解决歧义:
template <typename OP, typename... ARGS>
auto locked_call (OP op, ARGS... args) const -> decltype((list_.*op)(args...)) {
std::lock_guard<Mutex> g(lock_);
return (list_.*op)(args...);
}
void add (int p) {
void (List::*m)(const int &) = &List::push_back;
locked_call(m, p);
}