有没有办法通过模板参数自动解决重载方法?

时间:2018-12-13 22:53:28

标签: c++ multithreading c++11

我试图为列表操作编写通用方法锁定包装。我目前拥有的是:

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);

Try it online!

但是,我希望能够将要直接调用的方法传递到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);

Try it online!

模板或decltype是否可以巧妙地使用,以允许代码将方法名称简单地传递到locked_call中?


作为一种技巧,我可以使用宏通过自动生成lambda来实现简化的语法:

#define LOCKED_CALL(METHOD, ...) \
    locked_call([this,##__VA_ARGS__](){ \
        return list_.METHOD(__VA_ARGS__); })

但是我希望有一个等效的模板。

2 个答案:

答案 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);

它应该可以工作。

这需要支持。

或者:

#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);
}