2015-10-03 38 views
11

Tôi có một lớp có con trỏ hàm đến hàm hạt nhân, có thể thay đổi từ bên ngoài.C++ lambda - biến thành viên chụp

class Bar 
{ 
    public: 
    int i; 
} 

class Foo 
{ 
    public: 
    std::function<double()> kernel; 
    Bar bar;   
}; 

int main() 
{ 

    Foo f; 
    f.kernel = []() -> double { return i * i; }; //this is not working obviously 

} 

Làm cách nào để đạt được hành vi "được trình bày", ví dụ: đọc các biến lớp bên trong lambda. Tôi có thể bỏ qua nó bằng cách vượt qua f bên trong và viết f.bar.i, nhưng đó không phải là giải pháp rất tốt đẹp.

+1

Có gì sai với '[& f]() {return f.i * f.i; } '? –

+0

@KerrekSB Tôi đã chỉnh sửa câu hỏi –

+0

Vì vậy, về cơ bản bạn muốn gọi 'f.kernel()' và 'kernel' sẽ tự động được liên kết với' f' như nó là một hàm thành viên? – dhke

Trả lời

17

Trong C++ 14 bạn có thể viết nó như là,

f.kernel = [&i = f.bar.i]() -> double { return i * i; }; 

Nếu bạn không có C++ 14, bạn có cách khác có thể tạo ra một biến khác,

int &i = f.bar.i; 
f.kernel = [&i]() -> double { return i*i; }; 

Mặc dù không có gì sai khi chuyển số f và viết f.bar.i.

+0

Rất tốt. Nhưng điều này liên kết lambda hạt nhân với cá thể cụ thể đó của 'f', đúng không? Do đó nếu tôi làm 'f2.kernel = f.kernel' và gọi' f2.kernel() 'tôi nhận' i' từ 'f'? Có thể không phải là một vấn đề, mặc dù. – dhke

+1

chỉ là một FYI biên dịch ví dụ đầu tiên với g ++ -std = C++ 11 cho 'cảnh báo: lambda capture initializers chỉ có sẵn với -std = C++ 14 hoặc -std = gnu ++ 14' do đó nó là một tính năng C++ 14 – NathanOliver

+0

@NathanOliver Đã xóa "tin". @ dhke Có, nếu bạn sao chép 'kernel' từ' f' sang 'f2' thì bạn sẽ sử dụng cùng một hàm nếu bạn gọi nó từ một trong hai cá thể. – aslg

7

Có vẻ như you cannot do so. Không có cấu trúc để tạo lambda hàm thành viên.

Nhưng có lẽ bạn có thể làm theo @ đề nghị KerrekSB và ngoài công văn mà cuộc gọi đến vẫn nhận được chức năng thành viên:

class Foo 
{ 
public: 
    double kernel() 
    { 
     _kernel(*this); 
    } 

    std::function<double(Foo &)> _kernel; 
}; 


Foo f; 
f._kernel = [](Foo &f) -> double { return f.i * f.i; }; 
f.kernel() 

Lưu ý rằng bạn không thể đặt tên cho cả hai lĩnh vực kernel.

+0

Tôi thích giải pháp này quá. Bạn cũng có thể làm cho '_kernel' tĩnh để tất cả các cá thể sẽ chia sẻ cùng một" hàm thành viên ". – aslg

0

Hàm lambda không biết về i hoặc Bar. Làm thế nào nó có thể biết được? Bạn cần phải vượt qua một tham chiếu. Nếu bạn định nghĩa cơ thể hàm khác nhau để bạn có thể chuyển i như tham số và bạn gọi nó trong lớp bạn sẽ nhận được những gì bạn muốn.

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