Привязка параметров перед установкой указателя функции? - PullRequest
2 голосов
/ 11 августа 2011

Я хотел бы попробовать кое-что и объединить некоторый шаблонный код в одной из наших оболочек API динамической библиотеки.

По сути, я хотел бы сделать следующее:

typedef bool (*MyFPtrT)(long id, std::string const& name);
typedef boost::function<bool (long id, std::string const& name)> MyFObjT;
...

...
  MyFPtrT pDllFun = NULL;
  long x = 42; string s = "Answer"; // API input, not hardcoded
  MyFObjT f = boost::bind(pDllFun, x, s);
  ...
  return Call(f);
...

template<FT>
bool Call(FT f) {
  ...
  MyFPtrT pDllFun = (MyFunPtr)::GetProcAddress(...);
  f.setFunctionPointerButLeaveBoundParameters(pDllFun); // <- how??
  // Now call the correctly rigged up function object:
  return f();
}

Возможно ли это? (С Boost или иным?) ( C ++ 03 )

Ответы [ 2 ]

2 голосов
/ 11 августа 2011

Я не думаю, что это можно сделать напрямую, потому что bind создает новый объект, который принимает объект функции и аргументы по ссылке, и вы не можете перепривязать ссылки.

Однако вы можете легко написать свою собственную шаблонную оболочку функтора с переназначаемым указателем на функцию:

template <typename R, typename A, typename B>
struct ReAssFunctor
{
  typedef R(*FP)(A, B);

  ReAssFunctor(const A & a_, const B & b_) a(a_), b(b_) { }

  R operator()() const { return func(a, b); }

  FP function;

private:
  const A & a;
  const B & b;
};

[Редактировать:] Проверьте комментарии ниже; хранение ссылок, взятых с помощью const-ссылки в конструкторе, может быть опасным, поэтому будьте осторожны или сохраните a и b по значению, если хотите. [/]

Теперь вы можете инициализировать функтор с ранними аргументами:

ReAssFunctor<R, A, B> raf(a, b);

Затем назначьте указатель на функцию и вызовите:

raf.function = foo;
raf();

raf.function = goo;
raf();

Вы даже можете заменить оператор вызова на это:

  template <typename U>
  U operator()(U (f*)(A, B)) const { return f(a, b); }

А затем вызвать функтор с указателем функции в качестве аргумента:

raf(fp1);  // calls fp1(a,b);
raf(fp2);  // calls fp2(a,b);

В этом случае вам больше не нужен возвращаемый тип в качестве фиксированного параметра, но теперь вы не получаете нулевой оператор вызова. Выбирай.

1 голос
/ 12 августа 2011

Кажется, может работать следующее:

typedef bool (*MyFPtrT)(long id, std::string const& name);
typedef boost::function<bool (long id, std::string const& name)> MyFObjT;
...

...
  MyFPtrT pDllFun = NULL;
  long x = 42; string s = "Answer"; // API input, not hardcoded
  MyFObjT f = boost::bind(boost::ref(pDllFun), x, s);
  ...
  return Call(f, pDllFun);
...

template<class FT, class FP>
bool Call(FT f, FP& pDllFun) {
  pDllFun = (MyFunPtr)::GetProcAddress(...);
  return f();
}

Да, там есть опасные ссылки. В частности, f сохраняет ссылку на pDllFun. Это можно довольно легко смягчить: упакуйте их в один класс, чтобы время жизни было очевидно одинаковым.

...