Есть ли способ автоматически разрешать перегруженный метод с помощью параметра шаблона? - PullRequest
0 голосов
/ 14 декабря 2018

Я пытался написать оболочку блокировки метода общего назначения для операций со списком.Сейчас у меня есть:

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?


В качестве хака я могу использовать макрос для достижения упрощенного синтаксиса, автоматически генерируя лямбду:

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

Но я надеялся, что найдется шаблонный эквивалент.

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

Вы должны четко указать, какую перегрузку вы хотите использовать.

Вы можете заменить 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);
}
0 голосов
/ 14 декабря 2018
#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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...