вычет аргумента шаблона для указателя на функцию-член? - PullRequest
7 голосов
/ 30 января 2012

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

У меня есть следующий код, который работает именно так, как я хочу:

#include <iostream>

namespace thr {

template<typename T, T func>
struct delegate;

template<typename R,
         typename C,
         typename... A,
         R  (C::* mem_fun)(A...)>
struct delegate<R(C::*)(A...), mem_fun>
{ 
  delegate(C* obj_)
    : _obj(obj_)
  {}

  R operator()(A... a)
  {
    return (_obj->*mem_fun)(a...);
  }
 private:
  C* _obj;
};

} // namespace thr

struct foo
{
  double bar(int i, int j)
  { 
    return (double)i / (double)j;
  } 
};

int main()
{
  foo f;

  typedef thr::delegate<decltype(&foo::bar), &foo::bar> cb;      
  cb c(&f);

  std::cout << c(4, 3);
  return 0;
}

Однако использование не очень элегантно:

thr::delegate<decltype(&foo::bar), &foo::bar>

Я хотел бы использовать шаблон функции, который выводит параметры шаблона и возвращает экземпляр делегата; что-то вроде (этот код не компилируется):

template<typename C, typename T, T func>
thr::delegate<T, func> bind(T func, C* obj)
{
  return thr::delegate<decltype(func), func>(obj);
} 

Это позволит использовать более элегантный синтаксис:

auto cb = bind(&foo::bar, &f);

Можно ли вывести не типовой параметр в шаблоне функции?

Возможно ли то, что я пытаюсь достичь, возможно?

Ответы [ 2 ]

4 голосов
/ 30 января 2012

Поможет ли std :: function?http://www2.research.att.com/~bs/C++0xFAQ.html#std-function Ваш пример выглядит довольно близко.

Я думаю, что поставляемый компилятором STL делает довольно ужасные вещи, чтобы заставить его работать плавно.Вы можете посмотреть в качестве примера, прежде чем сдаться.

Редактировать: Я вышел и попробовал то, что вы пытаетесь достичь.Мой вывод - ошибка компиляции:

  • Возвращаемый тип привязки (делегата) должен давать указатель на член, потому что это ваше собственное требование.
  • bind должен принятьимя указателя на член, который должен быть элегантным (то есть ваше требование)
  • Компилятор требует, чтобы вы не затеняли параметр шаблона параметром функции или не использовали имя в обоих параметрах и типе возвращаемого значения.

Поэтому одно из ваших требований должно быть выполнено.

Редактировать 2: Я позволил себе сменить вашего делегата, так что связывание работает так, как вы пожелаете.хотя привязка может быть не вашим приоритетом.

#include <iostream>

namespace thr {


template<typename C,typename R,typename... A>
struct delegate
{ 
 private:
  C* _obj;
  R(C::*_f)(A...);
  public:
  delegate(C* obj_,R(C::*f)(A...))
    : _obj(obj_),_f(f)
  {}

  R operator()(A... a)
  {
    return (_obj->*_f)(a...);
  }

};

} // namespace thr

template<class C,typename R,typename... A> thr::delegate<C,R,A...> bind(R(C::*f)(A...),C* obj){
    return thr::delegate<C,R,A...>(obj,f);
}

struct foo
{
  double bar(int i, int j)
  { 
    return (double)i / (double)j;
  }
};

int main()
{
  foo f;
  auto c = bind(&foo::bar, &f);
  std::cout << c(4, 6);
  return 0;
}
1 голос
/ 30 января 2012

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

Дано:

template <size_t I> struct Integral { static size_t const value = I; };

Вы можете иметь:

template <size_t N>
Integral<N> foo(char const (&)[N]);

Но вы не можете иметь:

Integral<N> bar(size_t N);

В первом случае N как размер массива является частью типа аргумента, во втором случаеN - это сам аргумент.Можно заметить, что в первом случае N появилось в списке параметров шаблона сигнатуры типа.

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

Может существовать отсрочка экономии при использовании constexpr, которая может превратить обычное значение в постоянное соответствие для параметров шаблона:

constexpr size_t fib(size_t N) { return N <= 1 ? 1 : fib(N-1) + fib(N-2); }

Integral<fib(4)> works;

Но я не достаточно подкован, чтобы идти по этому пути ...

У меня, однако, есть простой вопрос: как вы думаете, почему это ускорит процесс?Компиляторы очень хороши в постоянном распространении и встраивании, вплоть до возможности встроенных вызовов виртуальных функций, когда они могут оценивать динамический тип переменных при компиляции.Вы уверены, что стоит потеть из-за этого?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...