2012-04-20 39 views
6

Tôi muốn có một lớp thực hiện operator() một số cách khác nhau dựa trên một tùy chọn được đặt trong lớp. Bởi vì điều này sẽ được gọi là một số lượng lớn thời gian, tôi không muốn sử dụng bất cứ điều gì mà chi nhánh. Lý tưởng nhất là, operator() sẽ là một con trỏ hàm có thể được thiết lập bằng một phương thức. Tuy nhiên, tôi không chắc điều này thực sự trông như thế nào. Tôi đã thử:Toán tử làm con trỏ hàm

#include <iostream> 

class Test { 
public: 
    int (*operator())(); 

    int DoIt1() { 
    return 1; 
    } 

    int DoIt2() { 
    return 2; 
    } 

    void SetIt(int i) { 
    if(i == 1) { 
     operator() = &Test::DoIt1; 
    } else { 
     operator() = &Test::DoIt2; 
    } 
    } 
}; 

int main() 
{ 
    Test t1; 

    t1.SetIt(1); 

    std::cout << t1() << std::endl; 

    t1.SetIt(2); 

    std::cout << t1() << std::endl; 

    return 0; 
} 

Tôi biết nó sẽ hoạt động nếu tôi tạo một con trỏ hàm khác và gọi hàm từ hàm operator(). Nhưng liệu có thể có hàm operator() chính nó là một con trỏ hàm? Một cái gì đó dọc theo dòng của những gì tôi đăng (mà không biên dịch)?

Đoạn mã trên cho:

test.cxx:5:21: error: declaration of ‘operator()’ as non-function

test.cxx: In member function ‘void Test::SetIt(int)’:

test.cxx:17:16: error: ‘operator()’ not defined

test.cxx:19:16: error: ‘operator()’ not defined

test.cxx: In function ‘int main()’:

test.cxx:30:19: error: no match for call to ‘(Test)()’

test.cxx:34:19: error: no match for call to ‘(Test)()’

+0

'int (operator())(); '... đúng cú pháp? – iammilind

+0

Hrm, nó phải là 'int (* operator())();' Tôi nghĩ, nhưng điều đó chỉ làm tăng toàn bộ các lỗi khác. Tôi sẽ chỉnh sửa mã. – tpg2114

+0

"Tôi không muốn sử dụng bất cứ thứ gì mà nhánh. Lý tưởng nhất, toán tử() sẽ là một con trỏ hàm" - Trên thực tế, các nhánh sẽ tốt hơn cho hiệu năng. CPU hiện đại có tỷ lệ thành công cao hơn 50% trong việc dự đoán nhánh nào sẽ được thực hiện; các con trỏ hàm có thể trỏ đến bất kỳ đâu và do đó khó hơn trên logic dự đoán. – MSalters

Trả lời

5

lớp của bạn cần phải bằng cách nào đó nhớ những gì con trỏ chức năng để sử dụng. Lưu nó như một thành viên lớp:

class Test 
{ 
public: 
    Test() : func(0) {} 

    int operator()() { 
     // Note that pointers to Test member functions need a pointer to Test to work. 
     return (this->*func)(); // undefined behavior if func == 0 
    } 

    void SetIt(int i) { 
     if(i == 1) { 
      func = &Test::DoIt1; 
     } else { 
      func = &Test::DoIt2; 
     } 
    } 

private: 
    int DoIt1() { 
     return 1; 
    } 

    int DoIt2() { 
     return 2; 
    } 

    // Typedef of a pointer to a class method. 
    typedef int (Test::*FuncPtr)(); 
    FuncPtr func; 
}; 

Tuy nhiên, trước khi bạn đi vào các nỗ lực để làm điều này, mã số hồ sơ của bạn đầu tiên và xem nếu nhánh qua switch hoặc if thực sự là một nút cổ chai (nó có thể không được!). Các bộ vi xử lý hiện đại có đặc tính hiệu suất rất trực quan, do đó các trình biên dịch có thể tạo ra mã tốt hơn bạn nghĩ. Cách duy nhất để đảm bảo rằng phân nhánh thực sự quá tốn kém để bạn sử dụng là lập hồ sơ cho mã của bạn. (Và bằng cách "profiling", tôi có nghĩa là "chạy thử nghiệm được thiết kế tốt", không phải "đi lên với linh cảm mà không thử nghiệm".)

+0

'typedef int (* FuncPtr)(); 'không đúng. Bạn cần phải viết 'typedef int (Test :: * FuncPtr)(); ' – Nawaz

+0

@Nawaz: Đã sửa lỗi. Cảm ơn bạn đã chỉ ra điều đó. –

+0

Vẫn còn vấn đề. Bạn cần phải viết '(this -> * func)();', không chỉ 'func();'. – Nawaz

1

Bạn có thể làm cho hàm operator() của bạn gọi một con trỏ khác. Trình tối ưu hóa sẽ loại bỏ hoàn toàn thêm hoàn toàn.

1

Một giải pháp được cung cấp bởi @In silico hợp lệ trong cả C++ 03 và C++ 11.

Dưới đây là một giải pháp cho C++ 11 chỉ:

std::function<int(Test*)> func; 

func = &Test::DoIt1; 

func(this); //this syntax is less cumbersome compared to C++03 solution 

A quick online full demo

Các vấn đề liên quan