2011-11-09 30 views
10

Tôi muốn biết liệu có thể sử dụng số lượng đối số được chuyển đến mẫu variadic làm trình giữ chỗ trong lệnh gọi hàm liên kết tăng ::.Tăng đối số giữ chỗ liên kết bằng số đối số Mẫu biến thể

Something như thế này:

template <typename ... Args> 

boost::bind(&function, this, anArg, _1));   //If Args count equals 1 
boost::bind(&function, this, anArg, _1, _2));  //If Args count equals 2 
boost::bind(&function, this, anArg, _1, _2, _3)); //If Args count equals 3 

Đây có phải là có thể?

Cảm ơn bạn

+4

Có một triển khai tốt đẹp về tiện ích make_indice tại đây: [http://preney.ca] (http://preney.ca/paul/2011/10/16/applying-stdtuple-to-functors-efficiently/) nhưng tôi đang gặp khó khăn trong việc tìm ra cách tôi có thể sử dụng nó với boost :: arg <> – Blizter

+0

Liên kết đó đã được đọc rất tốt, và hàm 'apply (Func, std :: tuple)' có thể có ích vào một ngày nào đó . –

+0

Tôi thấy 'typename ... Args'. Bạn đang sử dụng C++ 11? – kennytm

Trả lời

1

Chắc chắn là một cách chuyên môn hóa một phần. variadic của bạn không biết số lượng đối số ngay lập tức? bạn phải sử dụng đệ quy thời gian biên dịch, trong thời gian này, bạn có thể chồng các đối số của bạn bằng cách sử dụng boost :: mpl (hoặc đếm chúng bằng cách sử dụng một hằng số tích phân đơn giản). sau đó trong cuộc gọi đệ quy không-variadic cuối cùng của bạn (với 0 arg) bạn gọi mpl :: size trên thùng chứa của bạn (hoặc chỉ sử dụng bộ đếm tích phân nếu bạn chọn theo cách đó) để gọi một cuộc gọi như câu trả lời khác, mang tất cả đối số, cộng với một tham số mẫu tích phân ở đầu danh sách loại. và đó là những gì bạn chuyên. bạn thực hiện một người gọi cho mỗi số đối số sẽ gọi đúng ràng buộc theo số lượng đối số chuyên biệt của nó. (cấu trúc có thể gọi được (một phần) chuyên biệt theo số tham số mẫu tích phân đối số và mặc dù hàm Gọi lấy số lượng đối số tối đa, nó chỉ kết thúc lời gọi hàm ràng buộc đúng :: ví dụ liên kết (.. , _1, _2) cho Gọi là < 2, T1, T2, T3>) không khủng khiếp, nhưng tôi xác nhận rằng tôi đã sử dụng phương pháp này trong C++ 03 trong quá khứ.

0

Có thể bạn nên giải thích điều bạn muốn làm chi tiết hơn một chút. Nếu bạn chỉ đang tìm kiếm giải pháp để xử lý ba chữ ký khác nhau tùy theo loại thông số của chúng, bạn có thể làm như sau:

template<typename signature> 
struct callable; 

template<typename P0, typename P1, typename P2> 
struct callable<void (P0, P1, P2)> 
{ 
    void bind() 
    { 
     boost::bind(&callable::operator(), this, _1, _2, _3); 
    } 

    void operator()(P0, P1, P2) {} 
}; 
0

Đây không phải là câu trả lời cho vấn đề cụ thể, nhưng giải pháp tốt cho vấn đề bạn có thể đang cố giải quyết.

Tôi đã gặp sự cố tương tự khi triển khai cơ chế đại biểu chung. Giải pháp của tôi là sử dụng trình bao bọc trên đầu cuộc gọi liên kết, chuyên cho các biến thể. Trong khi nó không giải quyết vấn đề, nó chắc chắn giảm thiểu các mã dự phòng chỉ là cuộc gọi bind và quan trọng nhất mang lại cho tôi một hệ thống ủy quyền dựa trên tham số variadic mà tôi có thể sử dụng ở khắp mọi nơi.

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE> 
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(), CALLBACK_TARGET_CLASS* callbackTarget) 
{ 
    return std::bind(memberFunction, callbackTarget); 
} 

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0> 
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0), CALLBACK_TARGET_CLASS* callbackTarget) 
{ 
    return std::bind(memberFunction, callbackTarget, std::placeholders::_1); 
} 

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0, typename P1> 
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0, P1), CALLBACK_TARGET_CLASS* callbackTarget) 
{ 
    return std::bind(memberFunction, callbackTarget, std::placeholders::_1, std::placeholders::_2); 
} 



template<typename RETURNTYPE, typename... ARGS> 
struct Delegate 
{ 
    std::function<RETURN_TYPE (ARGS...)> callbackFunction; 

    template<class CALLBACK_TARGET_CLASS> 
    void Bind(CALLBACK_TARGET_CLASS* callbackTarget, RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(ARGS...)) 
    { 
     callbackFunction = BindFunction<CALLBACK_TARGET_CLASS, RETURN_TYPE, ARGS...>(memberFunction, callbackTarget); 
    } 

    void Callback(ARGS... params) 
    { 
     callbackFunction(params...); 
    } 
}; 

Cách sử dụng kết thúc chúng tôi tìm kiếm như thế này ..

class Foo 
{ 
public: 
    void Bar(int x); 
} 

Foo foo; 
Delegate<void, int> myDelegate; 

myDelegate.Bind(&foo, &Foo::Bar); 

myDelegate.Callback(3); 
0

Sử dụng _1, _2, ... trực tiếp là không thể với mẫu variadic. Thay vào đó, bạn cần phải sử dụng macro mở rộng.

Tuy nhiên, bạn có thể bao bọc các phần giữ chỗ trong một nhà máy có khuôn mẫu để lấy _1 với đối số mẫu 1, _2 cho 2, v.v ...

Triển khai như gcc/msvc đã xác định placeholders struct như templated (tương ứng std :: _ Placeholder và std :: _ Ph), do đó bạn có thể xác định bạn nhà máy theo cách này:

struct ph_factory { 
    template<size_t holder> 
    static std::_Placeholder<holder> make_ph() { 
     return std::_Placeholder<holder>(); 
    } 
}; 

này được xác định, bạn có thể mở rộng một gói thông số với tất cả các placeholders bạn muốn:

struct tester { 

    template<size_t ... holders> 
    void test(int val) { 
     auto callable = std::bind(&tester::call, this, val, ph_factory::make_ph<holders>()...); 
     callable('a', 42, 'c'); 
    } 

    void call(int v1, char c1, int v2, char c2) { 
     cout << "calling :" << v1 << " " << c1 << " " << v2 << " " << c2 << endl; 
    } 
}; 

Vì vậy, các mã sau đây sẽ đưa ra "gọi: 10 c 42 một"

int main() { 
    tester t; 
    t.test<3,2,1>(10); 
} 

Sử dụng các thủ thuật như make_indice sẽ cho bạn khả năng đạt được mục tiêu ban đầu của bạn.

+2

Không bao giờ dựa vào '_Names', chúng hoàn toàn riêng tư đối với việc triển khai và bạn không có lý do gì để nghĩ đến chúng. Có nhiều cách tốt hơn, một là bạn đặt tất cả các phần giữ chỗ vào một 'tuple' và' nhận được 'chúng với việc mở rộng gói. Mặt khác là bạn đăng ký trình giữ chỗ của riêng bạn (tiêu chuẩn cung cấp đặc điểm 'is_placeholder' vì lý do này, mà bạn có thể chuyên môn hóa. – Xeo

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