2015-02-19 21 views
5

Dưới đây tôi có một hàm mẫu có tên ProxyCall, chấp nhận một đối tượng, một hàm thành viên và các đối số của nó. Nó chỉ đơn giản là chuyển tiếp cuộc gọi đến hàm thành viên.Loại trừ tham chiếu const trong các chức năng khuôn mẫu

Tôi muốn có thể gọi chức năng mà không sử dụng trình định tính mẫu (tưởng tượng tấn các cuộc gọi như vậy với nhiều đối số). Loại khấu trừ chủ yếu là làm việc nhưng trình biên dịch (cả hai msvc và gcc 4.9) barf khi tôi cố gắng vượt qua tham số tham chiếu const như trong ví dụ.

#include <string> 

struct Widget { 
    void f(const std::string& s, bool b) {} 
}; 


template<typename T, typename... Args> 
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) { 
    (obj.*method)(std::forward<Args>(args)...); 
} 


int main(int argc, char* argv[]) 
{ 
    Widget w; 
    std::string s; 

    ProxyCall<Widget, const std::string&, bool>(w, &Widget::f, s, true); // OK 
    ProxyCall(w, &Widget::f, (const std::string&)s, true); // also OK 

    ProxyCall(w, &Widget::f, s, true); // ERROR: template parameter is ambiguous 
    return 0; 
} 

Câu hỏi của tôi là: Làm cách nào để tôi có thể tự động loại trừ các loại mà không cần sử dụng các định dạng mẫu rõ ràng hoặc truyền rõ ràng. Có vẻ như điều này nên được có thể xem xét rằng trình biên dịch đã biết rằng các loại đối số chính xác từ chữ ký của Widget :: f.

+1

'template void ProxyCall (T & obj, M method, Args && ... args) ' – zch

+1

hoặc cách khác' template void ProxyCall (T & obj, void (T: : * method) (Margs ...), Args && ... args) ' – zch

Trả lời

3
template<typename T, typename... Args> 
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) { 
    (obj.*method)(std::forward<Args>(args)...); 
} 

Args được rút ra từ cả hai đối số thứ hai và các đối số dấu để ProxyCall.
Trong trường hợp thứ ba của bạn, kể từ s không phải là const, Args được khấu trừ thành [std::string&, bool] (gọi lại quy tắc tham chiếu thu gọn và chuyển tiếp tham chiếu). Tuy nhiên, chữ ký chức năng thành viên rõ ràng là khác nhau. Vì vậy, hai loại khác nhau được suy ra cho loại đầu tiên trong Args, dẫn đến một thất bại khấu trừ.

Thay vào đó, làm cho cả hai loại tham số và các đối số độc lập - và chuyển tiếp đối số đối tượng, vì lợi ích của ref-vòng loại:

template<typename T, typename F, typename... Args> 
void ProxyCall(T&& obj, F method, Args&&... args) { 
    (std::forward<T>(obj).*method)(std::forward<Args>(args)...); 
} 
Các vấn đề liên quan