함수 포인터 또는 멤버 함수 포인터를 저장할 클래스를 작성했습니다 (한 번에 하나씩). 멤버 함수 포인터를 저장할 때 개체 포인터도 저장합니다 (리시버). 내가 사전에 객체의 유형이나 함수 서명도 모르는, 그래서 템플릿 유형 이름을 사용 멤버 함수 포인터에서 다른 유형으로 캐스팅하고 뒤로, 엄격한 앨리어싱 문제가 있습니까?
문제
입니다. 인수에 대해서는 가변성 템플릿을 사용합니다.내가이 유사한 코드가 : 필요 하나, 전역 함수 또는 멤버 함수 때문에
template <typename... Args>
class A
{
public:
template <typename Object, typename Ret>
A (Object *receiver, Ret (Object::*mem)(Args...)); // store the member function pointer
template <typename Ret>
A (Ret (*function)(Args...)); // store the global function pointer
void operator()(Args... args) const; // to call the function pointer
// ... more public stuff ...
private:
class UndefinedClass;
typedef void (Undefined::*MemFunPtrType)(Args...)
union
{
struct
{
MemFunPtrType memFunPtr; // the stored member function
void *receiverPtr; // the receiver object
void (*call)(void *, MemFunPtrType, Args...);
} member;
void (*funPtr)(Args...); // the stored global function
};
enum class Type {Function, Member} type;
};
을, 나는 union
안에 모든 것을 넣어. 생성자에서
void (Undefined::*)(Args...)
에 멤버 함수
mem
캐스팅하고 저장합니다. std :: function 구현에서이 트릭을 가져 왔습니다. 어떤 캡처와 람다를 사용
는
, 나는, 원래의 형태로 다시 객체와 기능 모두를 캐스팅하고 내가 그들을 호출 내부를 호출 할
typedef Ret (Object::*OriginalMemberType)(Args...);
// ...
member.call = [] (void *receiver, MemFunPtrType memFun, Args... args)
{
(static_cast<Object*>(receiver)->*reinterpret_cast<OriginalMemberType>(memFun))(args...);
}
나는 call
함수 포인터에서이 람다 저장을 operator()
. if-else 문장을 사용하여 형식 데이터를 비교하고 올바른 포인터를 호출합니다.
나는이 조금 짜증나는 알고 있지만, 그것을 작동합니다. 나는 많은 검사를 받았고 모두 검사를 통과합니다. 그러나 나는 엄격한 앨리어싱 것을 걱정하고 있습니다. 포인터 캐스팅을 많이하고 이것이 정의되지 않은 동작에 해당하는지 확실하지 않습니다.
질문 :Ret (Object::*)(Args...)
에서 void (UndefinedClass::*)(Args...)
으로 전송할 수 있습니까? (Ret개체 및 Arg은 템플릿 인수입니다. 참고 원래 형식으로 다시 캐스트하지 않고 개체를 호출하지 않습니다. 저장 전용입니다.
질문 :-fno-strict-aliasing
으로 컴파일해야합니까? 필자가해야한다면,이 클래스는 템플릿 클래스입니다.이 클래스를 사용하는 모든 프로젝트에 -fno-strict-aliasing
을 넣어야합니까? 어쩌면 sizeof(void (UndefinedClass::*)(Args...))
또는 그 대신에 비슷한 길이의 char
배열을 사용할 수 있습니다.
참고 :
- 나는 아치 리눅스에서 GCC 4.8.1를 사용합니다. 나는 C++ 11을 사용한다.
- 난 그냥 (내가 필요한 자리의 번호를 모르는) 표준 : 바인드에 사용 된 자리 표시자를 사용하는 것은 여기 표준 : 기능을 사용하지 않았다. 그리고 이것은 결국 좋은 습관과 학습입니다. std :: function을 사용하여이 작업을 수행하는 방법을 알고 있다면 대답은 매우 환영합니다.
- 는 사실, 동일한 서명 (신호/슬롯 종류의 프레임 워크)의 많은 "콜백"을 호출하기위한 표준 : : 벡터에서이 클래스를 사용합니다.
는 너무 감사드립니다. 나는이 엉망의 어떤 측면을 명확히 해줄 것이다. 필요하다면 :