Привязка к функции-члену - PullRequest
       32

Привязка к функции-члену

0 голосов
/ 28 августа 2018

Итак, вот ситуация: у меня есть два класса со статическим наследованием через CRTP. Базовый класс имеет метод run, который вызывает производный метод с шаблоном с переменными значениями, чтобы аргументы были гибкими. Теперь производный класс содержит функциональный объект. Производный класс имеет реализацию, которая вызывается базовым классом. Это может показаться ненужным, но в полной версии этого кода выполняется больше команд, чем просто включенная функция. Далее следует метод, который преобразует функцию в функцию bool (void) путем привязки всех переменных аргумента и экземпляра к методу CrtpBase::Run. Вот где у меня проблема. Я попробовал два разных подхода, версия с использованием лямбда закомментирована. Ни один из методов не работает. Моя цель - VoidFunction связать все параметры, чтобы я мог выполнять функцию в свободное время без аргументов. Что я тут не так делаю?

#include <functional>
#include <utility>

template <typename D>
struct CrtpBase {
  template <typename ... Args>
  bool Run(Args&& ... args) const {
    return static_cast<D&>(*this).Impl(std::forward<Args>(args) ...);
  }
};

template <typename ... Args>
struct CrtpDerived : public CrtpBase<CrtpDerived<Args ...>> {
  CrtpDerived(std::function<bool(Args ...)> function) : runable(std::move(function)) {}

  bool Impl(Args&& ... args) const {
    return this->runable(std::forward<Args>(args) ...);
  }

  std::function<bool(Args ...)> runable;
};

template <typename D, typename ... Args>
std::function<bool()> VoidFunction(CrtpBase<D> base, Args&& ... args) {
//  return [&base, &args ...]()->bool{return CrtpBase<D>::template Run<Args ...>(base);};
  return std::bind(CrtpBase<D>::template Run<Args ...>, base, std::forward<Args>(args) ...);
}

int main(int argc, char** argv) {
  std::function<bool(int&)> fn = [](int& a)->bool{a /= 2; return (a % 2) == 1;};
  CrtpDerived<int&> derived(fn);
  int x = 7;
  auto voided = VoidFunction(derived, x);
  bool out = voided();
  if ((x == 3) and (out == true)) {
    return EXIT_SUCCESS;
  } else {
    return EXIT_FAILURE;
  }
}

редактирует:

  1. Исправлена ​​опечатка в финальном тесте (out == false) стала (out == true)

1 Ответ

0 голосов
/ 28 августа 2018

Во-первых, с точки зрения компилятора CrtpBase<D>::template Run<Args ...> - это бессмысленная / неполная комбинация токенов. В C ++ такого синтаксиса выражений нет. Это выглядит как попытка сформировать указатель на член, но это требует явного применения & operator

return std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);

Во-вторых, этот актерский состав

static_cast<D&>(*this)

попытается отбросить постоянство. Это не разрешено в static_cast.

В-третьих, ваш

std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);

связывает подразумеваемый параметр this с параметром функции base. Это не сработает, поскольку base будет уничтожено, как только выйдет VoidFunction (или как только закончится вызывающее выражение) . Как правильно заметил @aschepler в комментариях, передавая base в значение CrtpBase<D>, нарезал исходный объект CrtpDerived<int&>. Передайте его по ссылке, а затем используйте &base в качестве аргумента для std::bind.

В-четвертых, std::bind не будет связываться «по ссылке» , и std::forward не поможет вам в этом. Это означает, что a внутри вашей лямбды fn не будет связано с x. Используйте std::ref, чтобы обойти это ограничение.

#include <functional>
#include <utility>

template <typename D>
struct CrtpBase {
  template <typename ... Args>
  bool Run(Args&& ... args) const {
    return static_cast<const D&>(*this).Impl(std::forward<Args>(args) ...);
  }
};

template <typename ... Args>
struct CrtpDerived : public CrtpBase<CrtpDerived<Args ...>> {
  CrtpDerived(std::function<bool(Args ...)> function) : runable(std::move(function)) {}

  bool Impl(Args&& ... args) const {
    return this->runable(std::forward<Args>(args) ...);
  }

  std::function<bool(Args ...)> runable;
};

template <typename D, typename ... Args>
std::function<bool()> VoidFunction(CrtpBase<D> &base, Args&& ... args) {
  return std::bind(&CrtpBase<D>::template Run<Args ...>, &base, std::forward<Args>(args) ...);
}

int main(int argc, char** argv) {
  std::function<bool(int&)> fn = [](int& a)->bool { a /= 2; return (a % 2) == 1; };
  CrtpDerived<int&> derived(fn);
  int x = 7;
  auto voided = VoidFunction(derived, std::ref(x));
  bool out = voided();
  if ((x == 3) && (out == false)) {
    return EXIT_SUCCESS;
  } else {
    return EXIT_FAILURE;
  }
}

И последнее: я не понимаю, почему вы ожидаете, что в итоге ваш out будет false.

...