Перегруженный указатель функции членства на шаблон

проект .Net OpenID является лучшей библиотекой для использования прямо сейчас, что я знаю о. Я думаю ТАК использовал его также. Источник включает демонстрационный ASP.NET проект MVC пользование библиотекой.

Scott Hanselman сделал сообщение о том, как использовать проект.Net OpenID в ASP.NET MVC.

6
задан user3708642 9 June 2014 в 17:05
поделиться

6 ответов

Ваш код в том виде, в каком он написан, не компилируется. Я сделал несколько "предположений" о том, что вы хотели сделать, и изменили код.

Подводя итог, вы можете вызвать правильную функцию, явно указав тип параметра функции:

connect<double> (&GApp::foo);

Если методы подключения являются членами шаблона класса, то это необходимо указать тип класса только один раз:

template <typename T> class A
{
public:
  template<class Arg1>
  void connect(void (T::*f)(Arg1)) 
  {
    //Do some stuff
  }

  void connect(void (T::*f)()) 
  {
    //Do some stuff
  }
};

class GApp
{
public:
    void foo() {}
    void foo(double d) {}
};


int main ()
{
  A<GApp> a;
  a.connect (&GApp::foo);            // foo ()
  a.connect<double> (&GApp::foo);    // foo (double)
}

ОБНОВЛЕНИЕ:

В ответ на новый образец кода вся информация передается. "Редким" случаем является случай 'signal_void', поскольку именно здесь сигнал имеет аргумент шаблона, а функция-член - нет. Поэтому мы рассматриваем этот пример отдельно, и на этом все готово. Теперь компилируется следующее:

template <class Arg = void>
class signal {};
signal<double> signal_double;
signal<> signal_void;

// Arg1 is deduced from signal<Arg1> and then we use it in the declaration
// of the pointer to member function
template<class T, class Arg1>
void connect ( signal<Arg1>& sig, T& obj, void (T::*f)(Arg1) ) {}

// Add special case for 'void' without any arguments
template<class T>
void connect (signal<> & sig, T& obj, void (T::*f)()) {}


void bar ()
{
  GApp myGApp;

  //Connecting foo()
  connect(signal_void, myGApp, &GApp::foo); // Matches second overload

  //Connecting foo(double)
  connect(signal_double, myGApp, &GApp::foo); // Matches first overload
}
6
ответ дан 9 December 2019 в 20:47
поделиться

Язык программирования C ++, 3E, раздел 7.7, стр. 159:

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

void f(int);
int f(char);

void (*pf1)(int) = &f;  // void f(int);
int (*pf2)(char) = &f;  // int f(char);
void (*pf3)(char) = &f; // error: no void f(char)

Насколько я знаю (не проверял), то же самое относится к функциям-членам. Таким образом, решение, вероятно, состоит в том, чтобы разделить на две строки:

connect((&GApp::foo)(double));

становится:

void (GApp::*tmp)(double) = &GApp::foo;
connect(tmp);

Никогда не вызывать переменные tmp ; -)

Я предполагаю, что приведение newacct также безопасно по той же причине . Приведение к void (GApp :: *) (double) определяется как то же самое, что и инициализация временного объекта типа void (GApp :: *) (double) . Поскольку для его инициализации используется выражение & GApp :: foo , Я ожидал, что к приведению будет применена та же магия, что и к любой другой инициализации с помощью перегруженной функции. Страуструп не говорит «инициализация переменной указателя на функцию», он говорит «инициализация указателя на функцию». Так что это должно включать временные.

Итак, если вы предпочитаете однострочный:

connect((void (GApp::*)(double))(&GApp::foo));

Однако я предполагаю, что стандарт имеет такое же представление о согласованности, как и я, и я не проверял.

5
ответ дан 9 December 2019 в 20:47
поделиться

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

connect((void (GApp::*)(double))&GApp::foo);

отказ от ответственности: haven не тестировал

1
ответ дан 9 December 2019 в 20:47
поделиться

Это работает,

    typedef void (GApp::*MemberFunctionType)(double); 
    MemberFunctionType pointer = &GApp::foo;


  connect(MemberFunctionType);

Почему?

РЕДАКТИРОВАТЬ

хм .. да. Это то же самое, что и решение newacct. Может кто подскажет решение пожалуйста?

0
ответ дан 9 December 2019 в 20:47
поделиться

Мой исходный код такой,

разъемы ....

template<class T, class Arg1>
void connect(signal<Arg1>& sig,T& obj, void (T::*f)()) 
{
//  sig.insert(new GFunction<T, Arg1>(&obj,f));
}

template<class T, class Arg1
void connect(signal<Arg1>& sig,T& obj, void (T::*f)(Arg1)) 
{
//  sig.insert(new GFunction<T, Arg1>(&obj,f));
}

Сигналы ...

signal<double> signal_double;
signal<> signal_void;

Приложение ...

class GApp
{
public:
    void foo() {}

    void foo(double d) {}
};

Наконец, подключение ...

//Connecting foo()
        connect(signal_void, myGApp, &GApp::foo()); //Ok

//Connecting foo(double)
        connect(signal_double, myGApp, &GApp::foo()); // but ERROR!

Для сигналов существуют классы шаблонов (которые здесь не упоминаются). Надеюсь, теперь ситуация прояснилась. (или он такой же, как предыдущий?). Это второе соединение будет РАБОТАТЬ, если нет foo () (только foo (double)). Это то, что меня задел мой код. : (

0
ответ дан 9 December 2019 в 20:47
поделиться

Использование библиотеки boost :: function ...

#include <boost/function.hpp>

template<class Arg1>
void connect(boost::function1<void, Arg1*> fn) 
{
    //Do some stuff
}

template<class Arg1>
void connect(boost::function2<void, Arg1*, double> fn) 
{
    //Do some stuff
}

class GApp
{
public:
    void foo() {}

    void foo(double d) {}
};


int main()
{
    boost::function1<void,GApp*> f1 = (void (GApp::*)(void)) &GApp::foo;
    boost::function2<void,GApp*,double> f2 = (void (GApp::*)(double)) &GApp:foo;
    connect(f1);
    connect(f2);
    return 0;
}
0
ответ дан 9 December 2019 в 20:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: