2014-05-06 59 views
0

這是一個簡單的委託類,只適用於格式無效類類別:: MethodType(的inputType &)的方法,但可以很容易地擴展到更通用的功能,不是簡單地顯示增加因爲它會太大。C++:性能上非模板委託類

class Delegate 
{ 
public: 
    Delegate(void) : Object(NULL), Argument(NULL) { } 
    virtual ~Delegate(void) { } 

    template <class ClassType, class InputType, void (ClassType::*MethodType)(InputType)> 
    void Create(ClassType* SetObject, void* SetArgument = NULL) 
    { 
     Object = SetObject; 
     Argument = SetArgument; 
     StaticCall = &CallMethod<ClassType, InputType, MethodType>; 
    } 

    template <class InputType> 
    inline void operator()(InputType InputValue) const 
    { 
     (*StaticCall)(Object, static_cast<void*>(InputValue)); 
    } 

    inline void operator()(void) const 
    { 
     (*StaticCall)(Object, Argument); 
    } 

protected: 
    typedef void (*FunctionCallType)(void*, void*); 

    void* Object; 
    void* Argument; 
    FunctionCallType StaticCall; 

private: 
    template <class ClassType, class InputType, void (ClassType::*MethodType)(InputType)> 
    static inline void CallMethod(void* SetObject, void* PassArgument) 
    { 
     (static_cast<ClassType*>(SetObject)->*MethodType)(static_cast<InputType>(PassArgument)); 
    } 
}; 

它是靈活的,可用於游泳池回調類,但有一個問題,我與它是不是一個虛擬的(在大載體中使用時,就像我打算或更慢),到目前爲止它看齊如果它被用作基類,則調用它。我正在尋找任何關於如何提高性能的建議,因爲我已經沒有想法,即使它影響功能。

我用(與-O3)最簡單的性能測量代碼爲:

class VirtualBase 
{ 
public: 
    virtual void TestCall(int* Data) {} 
}; 

class VirtualTest : public VirtualBase 
{ 
public: 
    VirtualTest() : Value(0) {} 

    void TestCall(int* Data) 
    { 
     Value += *Data; 
    } 
private: 
    int Value; 
}; 


class DelTest : public Delegate 
{ 
public: 
    DelTest() : Value(0) 
    { 
     Create<DelTest, int*, &DelTest::TestCall>(this); 
    } 

    void TestCall(int* Data) 
    { 
     Value += *Data; 
    } 
private: 
    int Value; 
}; 

int main(int argc, char **argv) 
{ 
    clock_t start; 
    int Value = 1; 

    VirtualBase* NewBase = new VirtualTest; 

    start = clock(); 
    for(size_t Index = 0; Index < 1000000000; ++Index) 
    { 
     NewBase->TestCall(&Value); 
    } 
    delete NewBase; 
    std::cout << ((std::clock() - start)/(double)CLOCKS_PER_SEC) << std::endl; 


    Delegate* NewDBase = new DelTest; 
    start = clock(); 
    for(size_t Index = 0; Index < 1000000000; ++Index) 
    { 
     NewDBase->operator()(&Value); 
    } 
    delete NewDBase; 
    std::cout << ((std::clock() - start)/(double)CLOCKS_PER_SEC) << std::endl; 

    return 0; 
} 

我要指出,我希望全班同學留下非模板,因爲它使得使用回調類難爲易在單個向量中迭代。

+0

你檢查[該難以置信的快C++委託(http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates)?它與你的非常相似,但一個區別是成員函數指針是編譯時常量,所以你不需要將它作爲運行時參數傳遞。 – iavr

+0

我會刪除'參數'。這是'std :: bind'的一個工作,在一個類中混合兩個不同的功能並不是一個好設計 - 委託本身足夠複雜。另外,對於一般情況,C++ 11中的可變參數實現不會比1參數版本長很多。 – iavr

+0

你試過std :: function嗎? –

回答

0

你可能想看看在CodeProject

這個 Lightweight Generic C++ Callbacks文章

一些來自鏈接文章的代碼,展示了使用函數模板做轉發的:

template<typename R, typename P1, typename P2> 
class Callback 
{ 
public: 
    typedef R (*FuncType)(void*, P1, P2); 
    Callback() : func(0), obj(0) {} 
    Callback(FuncType f, void* o) : func(f), obj(o) {} 
    R operator()(P1 a1, P2 a2) 
    { 
     return (*func)(obj, a1, a2); 
    } 

private: 
    FuncType func; 
    void* obj; 
}; 

template<typename R, class T, typename P1, typename P2, R (T::*Func)(P1, P2)> 
R Wrapper(void* o, P1 a1, P2 a2) 
{ 
    return (static_cast<T*>(o)->*Func)(a1, a2); 
} 

class Foo 
{ 
public: 
    float Average(int n1, int n2) 
    { 
     return (n1 + n2)/2.0f; 
    } 
}; 

float Calculate(int n1, int n2, Callback<float, int, int> callback) 
{ 
    return callback(n1, n2); 
} 

int main() 
{ 
    Foo f; 
    Callback<float, int, int> cb   
     (&Wrapper<float, Foo, int, int, &Foo::Average>, &f); 
    float result = Calculate(50, 100, cb); 
    // result == 75.0f 
    return 0; 
} 

有也是一個偉大的寫在stackoverflow here這將給你更好的見解。