템플릿에 대한 과부하 회원 기능 포인터
-
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);
연결 방법이 클래스 템플릿의 구성원 인 경우 클래스 유형을 한 번만 지정하면됩니다.
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)
}
업데이트:
새 코드 샘플에 대한 응답으로 모든 정보가 전달되고 있습니다. "희귀"케이스는 신호에 템플릿 인수가있는 곳이지만 멤버 함수는 그렇지 않습니다. 그러므로 우리는 특별한 사례와 그 다음에 끝났습니다. 다음은 다음과 같습니다.
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, p159 :
기능에 대한 포인터에 할당하거나 초기화하여 과부하 기능의 주소를 취할 수 있습니다. 이 경우 대상 유형은 과부하 된 함수 세트에서 선택하는 데 사용됩니다. 예를 들어:
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
, 나는 과부하 된 기능을 갖춘 다른 초기화에 적용되는 동일한 마법이 캐스트에 적용될 것으로 기대합니다. Stroustrup은 "포인터 간 기능 변수 초기화"라고 말하지 않으며 "포인터 간 기능 초기화"라고 말합니다. 따라서 임시를 포함해야합니다.
따라서 한 라이너를 선호한다면 :
connect((void (GApp::*)(double))(&GApp::foo));
그러나 표준이 저와 동일한 일관성에 대한 아이디어를 가지고 있으며 확인하지 않았다고 가정합니다.
포인터를 명시 적으로 캐스팅하여 다음과 같이 선택할 것을 알려줄 수 있습니다.
connect((void (GApp::*)(double))&GApp::foo);
면책 조항 : 테스트하지 않았습니다
이것은 작동하고 있습니다.
typedef void (GApp::*MemberFunctionType)(double);
MemberFunctionType pointer = &GApp::foo;
connect(MemberFunctionType);
왜 그런 겁니까 ?
편집하다
흠 .. 예. NewACCT의 솔루션과 동일합니다. 누구든지 솔루션 PLS를 줄 수 있습니까?
부스트 사용 :: 기능 라이브러리 ...
#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) 만). 그것이 내 코드가 나를 아프게하는 것입니다. :(