2010-04-05 26 views
6

Tôi đang cố gắng để giải quyết một vấn đề mà các chức năng ẩn danh làm nhiều, dễ dàng hơn nhiều, và đã tự hỏi nếu điều này là có thể trong C++.Có thể có chức năng ẩn danh C++ với tăng không?

Những gì tôi muốn làm là (cơ bản)

template<typename T> 
T DoSomething(T one, function<T(T)> dosomething) 
{ 
    return one + dosomething(5); 
} 

void GetMyVal(...) 
{ 
    DoSomething<int>(1, /*anonymous func here*/) 
} 

Ví dụ này là rất, rất đơn giản cho những gì tôi phải làm. Trong C# tôi sẽ làm p => p * 5. Tôi biết điều này rất dễ dàng với C++ 0x, nhưng tôi không thể sử dụng nó. Tôi cảm thấy rằng tôi sẽ có thể làm điều đó với một trong hai boost :: lambda, hoặc một compination của boost :: ràng buộc và tăng :: chức năng với placeholders, nhưng tôi dường như không thể có được nó để làm việc. Điều này có thể không khả thi và điều đó cũng tốt, nhưng hãy trả lời nếu không thể. Cảm ơn.

EDIT: Ok, có vẻ như trường hợp đơn giản của một int hoạt động tốt, còn cấu trúc phức tạp hơn thì sao? Vì vậy, hãy thử

struct NumHolder 
{ 
    int x; 
} 

template<typename T> 
T DoSomething(T one, function<T(NumHolder)> dosomething) 
{ 
    NumHolder temp; 
    temp = 5 
    return one + dosomething(temp); 
} 

void GetMyVal(...) 
{ 
    DoSomething<int>(1, /*anonymous func here*/) 
} 

Ở đây biểu thức C# của tôi sẽ nằm dọc theo dòng p => p.temp * 5. Có thể thực hiện điều này trong C++ khi tăng không?

EDIT 2: OK, bây giờ tôi chỉ tò mò: D Làm thế nào tôi sẽ gọi một hàm trong biểu thức lambda? Vì vậy, nếu chúng ta có

int ChangeVal(int mult) 
{ 
    return mult*5; 
} 

struct NumHolder 
{ 
    int x; 
} 

template<typename T> 
T DoSomething(T one, function<T(NumHolder)> dosomething) 
{ 
    NumHolder temp; 
    temp = 5 
    return one + dosomething(temp); 
} 

void GetMyVal(...) 
{ 
    DoSomething<int>(1, /*anonymous func here*/) 
} 

Trong C# Tôi có thể gọi p => ChangeVal (p). Cú pháp sẽ là gì đối với điều này với các biểu thức lambda C++?

+1

Có "nhiều, dễ dàng hơn nhiều" để tiết kiệm 5 dòng khai báo functor? – ima

+0

@ima: đây là phiên bản thực sự, đơn giản của những gì tôi cần làm. nếu không thì tôi có hàng tá functors. Trong trường hợp này nó dễ dàng hơn nhiều, tôi chỉ không biết cú pháp – Steve

+1

Nó không phải là cú pháp, đó là các mẫu rối cố gắng triển khai ngữ pháp tùy chỉnh trên đầu trang của C++. Có thể, nhưng tôi cố gắng để tưởng tượng tình huống mà việc tiết kiệm một số dòng mã có giá trị như vậy. Có một lòng từ bi với một số người đàn ông nghèo duy trì mã của bạn một hoặc hai năm sau ... – ima

Trả lời

5

Như Anders lưu ý trong câu trả lời của mình, đẩy mạnh :: lambda có thể hữu ích, nhưng các mã có thể trở nên khó đọc trong một số trường hợp. Nó do đó phụ thuộc vào những gì bạn muốn làm trong chức năng nặc danh của bạn.

Đối với trường hợp đơn giản như p => p * 5 bạn đề cập đến trong câu hỏi của bạn, có vẻ như với tôi rằng việc sử dụng Lambda hoặc Bind sẽ là hợp lý, mặc dù:

DoSomething(1, _1 * 5); 

Edit: ví dụ thứ hai của bạn chạm một khu vực nơi mà các cú pháp nhanh chóng tiết lộ: Quyền truy cập thành viên (dữ liệu hoặc chức năng). Bởi vì toán tử "dấu chấm" không thể bị quá tải trong C++, bạn phải sử dụng biểu thức liên kết để lấy "x" từ đối số:

DoSomething(1, bind(&NumHolder::x, _1) * 5); 

hoặc, với Boost.Lambda, sử dụng quá tải -> * điều hành:

DoSomething(1, &_1->* &NumHolder::x * 5); 

Chỉnh sửa 2: OK, lần cuối :) Trong câu hỏi cuối cùng của bạn, bạn viết rằng trong C#, bạn muốn viết p => ChangeVal(p), nhưng mã ở trên cho thấy một ChangeVal lấy một int, không phải là một NumHolder, vì vậy nó không rõ ràng những gì bạn có ý nghĩa.

Giả sử rằng ChangeVal mất một int và rằng bạn muốn anonymous function để làm tương đương với ChangeVal(the_arg.x), bạn muốn viết những dòng này với Boost.Lambda:

DoSomething(1, bind(&ChangeVal, &_1->*&NumHolder::x)); 

hay này với Boost.Bind (chỉ hoạt động với Lambda cũng vậy):

DoSomething(1, bind(&ChangeVal, bind(&NumHolder::x, _1)); 
+0

cảm ơn, là nó có thể sử dụng này với cấu trúc phức tạp hơn một chút? Tôi đã cập nhật câu hỏi của mình với một ví dụ – Steve

+0

Có thể gọi một hàm từ bên trong lambda không? Câu hỏi được cập nhật với một ví dụ. – Steve

+0

phiên bản liên kết của phiên bản cuối cùng hoạt động, phiên bản lambda đưa ra một lỗi về việc chuyển đổi functor – Steve

2

Không, nó không thể làm một cách đơn giản. boost :: lambda có thể giúp, nhưng theo ý kiến ​​của tôi, mã rất khó đọc khi sử dụng nó vì vậy tôi sẽ tránh nó.

Tôi nghĩ rằng tương đương với C# p=>p*5 sẽ là _1*5, nhưng tôi đã chỉ xem xét nó một thời gian ngắn vì vậy tôi không chắc chắn. Đối với những thứ đơn giản nó hoạt động, nhưng ngay sau khi bạn cần cấu trúc điều khiển, bạn sẽ phải sử dụng một tập hợp các cấu trúc điều khiển khác dựa trên chức năng, thay vì bắt buộc. Tôi thấy điều này khác với mã C++ bình thường mà tôi quyết định cho bản thân mình rằng nó không đáng để sử dụng nó, bởi vì nó làm cho mã khó đọc cho người khác.

+0

bạn có biết làm thế nào để làm điều đó trong lambda tăng? – Steve

0

tăng không mở rộng cú pháp của C++. không có hàm ẩn danh nào trong C++.

+1

Tôi biết không có thực sự anon funcs trong c + +. Tôi đã tự hỏi nếu tăng đã có một cách giả mạo nó – Steve

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