2012-11-28 4 views
1

앞으로의 교과 과정에서 더 많은 성능/메모리 효율을 끌어낼 수 있는지 가상으로 보는 것을 피하려고합니다. 이 문제는 StateManager를 구현하고자 할 때 시작되었습니다 (코스 프로토 타입은 작은 게임 임).정적 멤버 초기화 링크 오류

나는 현재 상태의 멤버 함수 호출을 "statify"하기위한 템플릿을 만들 수 있습니다.

예 상태이 될 것입니다 :

struct TestState { 
    bool update(float delta) { 
     return true; 
    } 
}; 

지금 국가 관리자가 모든 국가의 클래스를 가지고 업데이트 기능을 결합 할 수 있어야한다. boost :: bind 및 boost :: function을 사용하여이 작업을 쉽게 수행 할 수 있었지만 가상에 비해 성능이 저하되었으므로 부스트없이 가능할 지 알고 싶었습니다.

State는 정적 함수 만 포함하는 클래스/구조체이지만 이론적으로는 비경제적이고 더 정적 인 초기화 혼란이 추가된다는 것은 이론적으로 쉽습니다.

class StateManager 
{ 
public: 
    template <typename S> static void set(S* state) 
    { 
     #define UPDATE_ID 0 

     StateFunctionHandler<UPDATE_ID, S, bool, float>::bind(std::mem_fun1(&S::update), state); 
     m_funcUpdate = StateFunctionHandler<UPDATE_ID, S, bool, float>::exec; 
    } 
    static bool update(float delta) 
    { 
     return m_funcUpdate(delta); 
    } 
    typedef bool (*funcUpdate)(float); 
private: 
    static funcUpdate m_funcUpdate; 
}; 

StateFunctionHandler

가 StateFunctionHandler의 고정 부재의 멤버 함수를 배치 할 책임이 템플릿이다

에서 StateManager 현재 버전이된다. 템플릿의 첫 번째 매개 변수는 반환 유형 및 인수가 같은 함수에 대해 여러 개의 템플릿을 사용하도록하는 ID입니다.

코드 그것은 다음과 같습니다

template <int ID, typename S, typename R, typename A> 
struct StateFunctionHandler 
{ 
    static void bind(std::mem_fun1_t<R, S, A> f, S* s) 
    { 
     func = f; 
     pState = s; 
    } 
    static R exec(A arg) 
    { 
     return func(pState, arg); 
    } 

    static std::mem_fun1_t<R, S, A> func; 
    static S* pState; 
}; 

문제는 이제 우리가 그들을 초기화하는 컴파일러를 강제 할 필요가 있기 때문에, 사용 된 경우에 StateFunctionHandler의 템플릿 정적 멤버를 초기화하는 것입니다. 정적 멤버는 초기화받을 이러한 클래스에 관련된 CPP 파일에서

:

template <int ID, typename S, typename R, typename A> std::mem_fun1_t<R, S, A> StateFunctionHandler<ID, S, R, A>::func; 
template <int ID, typename S, typename R, typename A> S* StateFunctionHandler<ID, S, R, A>::pState = NULL; 

StateManager::funcUpdate StateManager::m_funcUpdate = NULL; 

하지만 링크 오류 StateFunctionHandler에 대한 (LNK2001) : FUNC과를 얻을 수는 :: pState은, 그래서 컴파일러는없는 것 같다 StateFunctionHandler의 정적 멤버를 초기화했습니다.

를 사용하는 경우 : 다시

TestState* t = new TestState(); 
StateManager::set(t); 
StateManager::update(0.1f); 

은 분명히, 내가 부스트를 사용하지 않을 수 있도록,이 내가이 사용 사례에서 가상 함수를 방지하고 성능을 가질 수 있는지 확인하는 실험이다 게다가.

+0

링크 오류는 일반적으로 모든 개체를 연결하지 않았 음을 의미합니다. 초기화 순서가 중요하지만 런타임 오류가 발생합니다. – Nim

+0

나는 이것이 실험이라는 것을 알고 있지만 코드가 성능에 미치는 영향을 알아보기 위해 프로파일을 작성 했습니까? 최적화 문제는 종종 코드 품질에 영향을 미치며 대개 코드의 일부분에서만 필요합니다. 당신이하는 일은 정말로 과도한 것처럼 보입니다. "조기 최적화는 모든 악의 뿌리입니다."라는 말을 기억하십시오. – RonaldBarzell

+0

바인드가 호출 될 때 pState/func가 존재하지 않는 것처럼 보이기 때문에 링크 오류는 바인드 함수의 할당과 관련됩니다. 코드를 컴파일 할 수 없으면 성능을 비교할 수 없습니다. 이를 실험하는 주된 이유는 컴파일러가 비 가상 함수를 더 잘 최적화 할 수 있기 때문입니다. 실험적이기 때문에 나는 사악 해지는 것을 싫어합니다. – niktehpui

답변

1

정적 템플릿 클래스 멤버 초기화를 헤더 파일로 옮겨야합니다.

비 정적 템플릿 클래스 멤버와 마찬가지로 템플릿을 인스턴스화하는 모든 번역 단위에서 볼 수 있어야합니다.