Перегруженный указатель функции-члена на шаблон
-
11-09-2019 - |
Вопрос
Я пытаюсь хранить указатели на функции-члены с помощью шаблонов, подобных этому:(Это упрощенная версия моего реального кода)
template<class Arg1>
void connect(void (T::*f)(Arg1))
{
//Do some stuff
}
template<class Arg1>
void connect(void (T::*f)())
{
//Do some stuff
}
class GApp
{
public:
void foo() {}
void foo(double d) {}
};
Затем я хочу сделать следующее для всех перегруженных методов в GApp:
connect(&GApp::foo);
Призывая к этому для foo()
это нормально, но как я могу вызвать это для foo(double d)
?Почему следующее не работает?
connect((&GApp::foo)(double));
Это даст мне
синтаксическая ошибка :Слову "double" должно предшествовать ')'
Я не понимаю синтаксис, который здесь должен быть использован.Возможно, это глупый вопрос, но может ли кто-нибудь помочь мне в этом?
Решение
Ваш код в том виде, в каком он написан, не компилируется.Я сделал несколько "предположений" о том, что вы хотели сделать, и изменил код.
Подводя итог, вы можете вызвать правильную функцию, явно указав тип параметра функции:
connect<double> (&GApp::foo);
Если методы connect являются членами шаблона класса, то указать тип класса необходимо только один раз:
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
}
Другие советы
Язык программирования 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));
Однако я предполагаю, что стандарт имеет ту же идею согласованности, что и я, и я не проверял.
Вы можете попробовать явно привести указатель, чтобы сообщить ему, какой из них выбрать, вот так:
connect((void (GApp::*)(double))&GApp::foo);
Отказ от ответственности:еще не тестировал это
Это работает,
typedef void (GApp::*MemberFunctionType)(double);
MemberFunctionType pointer = &GApp::foo;
connect(MemberFunctionType);
Почему это так ?
Редактировать
хм..да.Это то же самое, что и решение newacct.Кто-нибудь может дать решение, пожалуйста?
Использование boost:: библиотека функций...
#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;
}
Мой Исходный код выглядит следующим образом,
соединители....
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)).Это то, из-за чего мой код причинил мне боль.:(