2009-03-14 26 views
7

tôi đã tự hỏi nếu có một cách để làm điều này trong C + +?Bản đồ chức năng tăng cường của các loại khác nhau?

void func1(const std::string& s) 
{ 
std::cout << s << std::endl; 
} 

void func2(int me) 
{ 
std::cout << me << std::endl; 
} 

int main() 
{ 
std::map<std::string, boost::function<???> > a_map; 

a_map["func1"] = &func1; 
a_map["func1"]("HELLO"); 

} 

Có cách nào để làm những gì tôi có ở trên bằng chức năng tăng cường và bản đồ không?

+0

Giả sử bạn có thể lưu trữ các giá trị và chức năng trong bản đồ, làm thế nào mà bạn muốn truy cập để lập bản đồ các yếu tố? – bayda

Trả lời

2

Có nhiều cách để lưu trữ các chức năng, vấn đề là, để có thể gọi hàm với đối số bạn muốn, bạn phải biết gọi chữ ký của hàm anyways và nếu bạn có thông tin đó, bạn cũng có thể sử dụng các bản đồ riêng biệt hoặc sử dụng đối tượng phức tạp hơn hàm boost ::.

Nếu bạn sẵn sàng để làm một chút công việc và có một số hữu hạn các chữ ký, bạn chỉ có thể làm điều gì đó như thế này:

class MultiFunc 
{ 
protected: 
    MultiFunc() {} 

public: 
    typedef void (*stringFunc)(const std::string&); 
    typedef void (*intFunc)(int); 

    static MultiFunc *Create(stringFunc function); 
    static MultiFunc *Create(intFunc function); 

    virtual void operator()(const string &) { throw exception(); } 
    virtual void operator()(int) { throw exception(); } 
    virtual ~MultiFunc(); 
}; 

class MultiFuncString : public MultiFunc 
{ 
private: 
    stringFunc Function; 
public: 
    MultiFuncString(stringFunc function) : Function(function) {} 
    virtual void operator()(const string &arg) { Function(arg); } 
}; 

class MultiFuncInt : public MultiFunc 
{ 
private: 
    intFunc Function; 
public: 
    MultiFuncInt(intFunc function) : Function(function) {} 
    virtual void operator()(int arg) { Function(arg); } 
}; 

MultiFunc *MultiFunc::Create(MultiFunc::stringFunc function) 
{ 
    return new MultiFuncString(function); 
} 
MultiFunc *MultiFunc::Create(MultiFunc::intFunc function) 
{ 
    return new MultiFuncInt(function); 
} 

void func1(const std::string& s) 
{ 
std::cout << s << std::endl; 
} 
void func2(int me) 
{ 
std::cout << me << std::endl; 
} 

int main() 
{ 
    map<string, MultiFunc *> a_map; 
    a_map["func1"] = MultiFunc::Create(&func1); 
    (*a_map["func1"])("Hello"); 
    a_map["func2"] = MultiFunc::Create(&func2); 
    (*a_map["func2"])(3); 

    // Remember to delete the MultiFunc object, or use smart pointers. 
} 

đầu ra này:

 
Hello 
3 

Thật không may, bạn không thể tạo các chức năng ảo được tạo khuôn mẫu hoặc bạn dễ dàng khái quát hóa tất cả điều này.

2

Bạn có thể không sử dụng được std::map vì nó là một vùng chứa đồng nhất. Hãy thử, một cái gì đó như boost::variant (chúng hỗ trợ kiểu khách truy cập) hoặc boost::tuple

+0

boost :: biến thể là cách để đi đến đây. Tôi đã làm điều này trong mã và nó hoạt động tuyệt vời. Trong một vài dòng (của MPL), tôi hỗ trợ một bản đồ int, float, double, String và một function0 của mỗi loại đó. –

0

cửa hàng giao diện:

struct IStringData 
{ 
    virtual std::string get() const = 0; 
    virtual ~IStringData() {} 
}; 

và làm implementaions, một chỉ sẽ tổ chức chuỗi giá trị, thực hiện khác sẽ lưu trữ functor, có thể bạn sẽ có các triển khai khác trong tương lai.

0

No. Bạn không thể. Kể từ khi tăng :: chức năng không phải là đa hình, nó bị phá vỡ ở đó. (Phải mất một tập hợp các kiểu đối số cố định.)

Có nói về công việc theo hướng đó trên danh sách thư tăng, vì vậy, hãy tìm kiếm lưu trữ và xem có mã nào bạn có thể dùng không.

Cách giải quyết là sử dụng hàm boost :: nhưng sau đó bạn cần phải thêm vào bản đồ chứ không phải chức năng thực của bạn (tức là func1/func2) nhưng chức năng gửi sẽ trích xuất loại từ bất kỳ vùng chứa nào và gọi hàm thực . (Và bails nếu nó sai, cũng giống như trong bất kỳ langugage năng động.)

2

Những gì bạn đang cố gắng để làm âm thanh một chút lạ. Thông thường, bạn sẽ có một vùng chứa là một tập hợp các kiểu trừu tượng hoặc các đối tượng hoặc các hàm có cùng chữ ký. Nếu không, làm cách nào bạn biết cách gọi hàm khi bạn đang lặp lại vùng chứa? Tôi thích để làm cho container một bộ sưu tập các đối tượng chức năng với một chữ ký được biết đến, sau đó sử dụng Boost.Bind để lưu trữ các đóng cửa gọi hàm với các đối số bổ sung.

Ví dụ:

typedef boost::function<void, void> Function; 
typedef std::map<std::string, Function> Functions; 

Functions functions: 

void foo() 
{ 
    ... 
} 

functions["foo"] = foo; 

void bar(std::string &s) 
{ 
    ... 
} 

// binds the value "hello" to the s parameter 
functions["bar"] = boost::bind(bar, "hello"); 
Các vấn đề liên quan