локальная переменная как аргумент шаблона нетипа

Я хочу сделать что-то вроде следующего:

Example(&Class::MemberFunction, this));

//...

template<class T_CLASS>
inline static void Example(void (T_CLASS::*MemberFunctionPointer)(), T_CLASS* InstancePointer)
{
  SomeClass<T_CLASS>::Bind<MemberFunctionPointer>(InstancePointer);
}

Но я получаю сообщение об ошибке: *параметр шаблона 'T_MEMBER_FUNCTION': 'MemberFunctionPointer': локальная переменная не может использоваться в качестве аргумента, отличного от типа*

Любые решения для этой проблемы? Я хочу предоставить более простой способ вызова "Bind"

Спасибо, Мирко

//редактировать:

Я хочу, чтобы MemberFunctionPointer был параметром шаблона, отличным от типа, потому что в «Bind» он мне снова нужен в качестве аргумента шаблона. Как вы писали в своих ответах, в моем случае MemberFunctionPointer является переменной, и ее значение неизвестно во время компиляции. Но MemberFunctionPointer всегда указывает на одну и ту же функцию. Есть ли способ, например, сделать его постоянным, чтобы компилятор знал об этом во время компиляции?


person Mirco    schedule 29.06.2011    source источник
comment
Пожалуйста, посмотрите на этот очень похожий вопрос stackoverflow.com/q/6041570   -  person sharptooth    schedule 29.06.2011


Ответы (4)


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

Помните: шаблон — это тип. И типы должны быть определяемыми во время компиляции.

Вероятно, вам следует передать указатель члена в качестве аргумента функции Bind.

person Nicol Bolas    schedule 29.06.2011

Я не совсем уверен, чего вы пытаетесь достичь?

Если MemberFunctionPointer является переменной, значение которой неизвестно во время компиляции и, например, может зависеть от некоторого поведения пользователя, то ее нельзя использовать в качестве аргумента шаблона.

Если, с другой стороны, MemberFunctionPointer можно вывести во время компиляции, вы должны передать его как аргумент шаблона, а не как параметр функции. Рассмотрим следующий пример:

(используйте Bind и call в первом случае; во втором случае используйте StaticBind и callStatic)

#include <stdio.h>

class X {
  public:
    int x;
    void foo() {printf("foo\n");}
    void bar() {printf("bar\n");}
};

template <typename T>
class SomeClass {
  public:
    static void Bind(void (T::*MemberFunctionPointer)(), T *obj) {
      (obj->*MemberFunctionPointer)();
    }
    template <void (T::*MemberFunctionPointer)()>
    static void StaticBind(T *obj) {
      (obj->*MemberFunctionPointer)();
    }
};

template <class C>
static inline void call(void (C::*MemberFunctionPointer)(), C *obj) {
  SomeClass<C>::Bind(MemberFunctionPointer,obj);
}

template <class C, void (C::*MemberFunctionPointer)()>
static inline void callStatic(C *obj) {
  SomeClass<C>::template StaticBind<MemberFunctionPointer>(obj);
}

int main() {
  X obj;
  call<X>(&X::foo,&obj);
  callStatic<X,&X::bar>(&obj);
  return 0;
}
person CygnusX1    schedule 29.06.2011
comment
Я хочу, чтобы это было выведено во время компиляции, но я не знаю, как это сделать. Так что второй случай подходит лучше... только я пытаюсь обеспечить вызов метода, который не принимает никаких аргументов шаблона. - person Mirco; 29.06.2011
comment
В этом случае вы действительно можете использовать первый метод, а также встроить все функции. Но тогда функция Bind, как показано в примере, должна принимать указатель на функцию-член по параметру, а не по параметру шаблона. С включенной оптимизацией она должна сводиться к константе, и вы не должны испытывать накладных расходов во время выполнения. Параметр шаблона <C> функции call может быть фактически выведен из переданных параметров, поэтому вы можете пропустить его при вызове. Я дал это там для ясности. - person CygnusX1; 29.06.2011

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

Если вы уже знаете этот указатель во время компиляции, вы можете превратить параметр времени выполнения указателя функции в параметр шаблона:

template<class T_CLASS, void(T_CLASS::*MemFunPtr)()>
void Example(T_CLASS* InstancePointer) {...}

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

person sellibitze    schedule 29.06.2011
comment
Спасибо, это то, что я хочу сделать. Насколько я понимаю, нет возможности передать MemFunPtr как обычный параметр и избежать передачи его в качестве параметра шаблона в пример, верно? - person Mirco; 29.06.2011

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

template<typename T_FUNC_PTR, class T_CLASS>
inline static void Example(T_FUNC_PTR fPtr, T_CLASS* InstancePointer)
{
  SomeClass<T_CLASS>::Bind<T_FUNC_PTR>(fPtr, InstancePointer);
}

т. е. позволить компилятору вывести тип указателя функции (ПРИМЕЧАНИЕ: вам также придется распространить указатель на функцию), чтобы вызвать

Example(&foo::bar, foo_inst);

Это не проверено и не приходит мне в голову, поэтому синтаксис может немного отличаться...

РЕДАКТИРОВАТЬ: вот более простой пример для демонстрации концепции:

#include <iostream>
struct foo
{
  void bar() { std::cout << "foo::bar()" << std::endl; }
};

template<typename T_FUNC_PTR, typename T_CLASS>
void exec(T_FUNC_PTR ptr, T_CLASS& inst)
{
  (inst.*ptr)();
}

int main(void)
{
  foo inst;
  exec(&foo::bar, inst);
}
person Nim    schedule 29.06.2011
comment
Ваше первое предложение предполагает, что в качестве параметров шаблона можно использовать только типы. Это неправда. Система шаблонов C++ также принимает нетиповые параметры. Но это должны быть константы времени компиляции либо целочисленного типа, либо указателя/ссылки на что-то с внешней связью. - person sellibitze; 29.06.2011
comment
@sellibitze, правда? Я явно заявил, что переменная является переменной, а не типом... Думаю, я буду немного более явным... - person Nim; 29.06.2011
comment
Спасибо за ответ. Как я описал выше, я хочу, чтобы мой указатель функции-члена был нетиповым аргументом шаблона. При передаче его как одного, как в моем вызове Bind, проблем нет, но я хотел бы иметь более простую в использовании функцию-оболочку. Пример, который не принимает параметры шаблона. Пример должен получить MemberFunctionPointer в качестве параметра и передать его в Bind в качестве параметра шаблона, отличного от типа. Он всегда указывает на одну и ту же функцию, и я хочу, чтобы компилятор знал об этом во время компиляции. Это возможно? - person Mirco; 29.06.2011
comment
@Micro, это то, что делает мой пример, когда вызывается exec, я явно не указываю типы, компилятор работает на основе аргументов. В вашем коде вам не нужен Bind<T_FUNC_PTR>, компилятор может обработать его на основе переданного аргумента (fPtr) - person Nim; 29.06.2011
comment
@Nim, поправьте меня, если я ошибаюсь, но в вашем коде exec я не мог использовать ptr в качестве параметра шаблона, отличного от типа, что я и хочу сделать для вызова Bind. Я не хочу передавать тип указателя функции, а сам указатель функции в качестве аргумента. - person Mirco; 30.06.2011
comment
@Micro, вы не можете этого сделать, лучше всего передать сам указатель функции и позволить компилятору определить соответствующий тип в Bind. - person Nim; 30.06.2011