2012-03-12 28 views
6

Có thể hạn chế kiểu chụp lambda được đưa ra làm tham số không?
Ví dụ: Có thể chỉ lấy lambdas không nắm bắt bất kỳ điều gì bằng cách tham chiếu không?Ràng buộc bắt giữ lambda C++

template <typename F> 
void f(const F& lambda) // F must be a lambda that do not capture by ref 
{ 
    ::: 
} 
+2

Khi đối tượng đóng cửa chạm vào chức năng của bạn, nó đã được xây dựng, và bạn không có ý tưởng gì bên trong ruột của nó, vì chúng là riêng tư. Nhưng trong trường hợp bạn đang tự hỏi, lambda chắc chắn không thể nắm bắt bất cứ điều gì * sau thực tế *, và đặc biệt không có gì từ bên trong * hàm * 'f' của bạn. –

+5

Điều này sẽ là vô nghĩa, vì việc chụp con trỏ theo giá trị cũng nguy hiểm như việc chụp tham chiếu. –

+0

@BenVoigt Đúng vậy. – log0

Trả lời

5

MSalters lưu ý rằng "lambda không bắt được có thể được chuyển đổi thành con trỏ thành hàm." Điều đó có nghĩa là gì? Đối tượng lambda sẽ khớp với một con trỏ trỏ đến kiểu tham số hàm.

Thật khó để dịch loại lambda thành con trỏ thành hàm. Đây là nỗ lực của tôi trong việc triển khai tuân thủ. Đó là hơi hackish.

#include <type_traits> 

template< typename fn > 
struct ptmf_to_pf; 

template< typename r, typename c, typename ... a > 
struct ptmf_to_pf< r (c::*) (a ...) const > 
    { typedef r (* type)(a ...); }; 

// Use SFINAE to hide function if lambda is not convertible to function ptr. 
// Only check that the conversion is legal, it never actually occurs. 

template< typename lambda > 
typename std::enable_if< std::is_constructible< 
     typename ptmf_to_pf< decltype(&lambda::operator()) >::type, 
     lambda >::value >::type 
f(lambda arg) { 
    arg("hello "); 
    arg("world\n"); 
} 

#include <iostream> 

int main() { 
int x = 3; 
    f([](char const *s){ std::cout << s; }); // OK 
    f([=](char const *s){ std::cout << s; }); // OK 
    f([=](char const *s){ std::cout << s << x; }); // error 
} 

Điều này sẽ không chấp nhận con trỏ hàm làm đối số trực tiếp, vì thông số mẫu cần phải giải quyết cho một hàm. Bạn có thể làm cho nó làm như vậy bằng cách cung cấp một chuyên môn cho ptmf_to_pf chấp nhận con trỏ đến các loại chức năng.

Ngoài ra, như bản trình diễn cho thấy, nó sẽ không chấp nhận lambdas nắm bắt bất cứ điều gì theo giá trị, cũng như bằng cách tham chiếu. Không có cách nào trong C++ để hạn chế cụ thể như vậy.

+0

Tại sao không chỉ truyền lambda như một con trỏ hàm, mà không có mẫu? – perreal

+1

@perreal: Nếu bạn biết loại con trỏ hàm mong muốn, hãy làm như vậy. Trong trường hợp chung, điều này không được biết. – Potatoswatter

5

Có lẽ bạn đang hiểu lầm hành vi chụp của biểu thức lambda: Một đối tượng đóng cửa cũng giống như một đối tượng functor nêu ra, vì vậy

struct Fun 
{ 
    Fun (int & a) : n(a) { } 
    int operator()(...) { ... } 
private: 
    int & n; 
}; 

int q; 
Fun f(q); 
f(...); 

là chính xác giống như

int q; 
auto f = [&q](...) -> int { ... }; 
f(...); 

Khi đối tượng đóng cửa được xây dựng, tất cả việc chụp và ràng buộc được hoàn thành và vĩnh viễn bị khóa vào đối tượng.

Nếu bây giờ bạn chuyển đối tượng sang một số nơi khác, như call_me(f), thì chức năng người nhận không có kết nối với việc xây dựng đối tượng functor hoặc đóng.

+1

Đó là sự thật, nhưng loại trình biên dịch tạo ra lambda chứa tất cả các chi tiết về cách bắt giữ xảy ra. Người ta có thể dễ dàng tưởng tượng một hệ thống siêu dữ liệu cho phép nội suy của loại đó để xem liệu có bất kỳ thành viên tham chiếu nào không (hoặc liệu hàm tạo có bất kỳ tham số tham chiếu nào) hay không. –

+0

@BenVoigt yes có thể là một đặc điểm của đối tượng functor ... – log0

3

Tấn công gián tiếp: Chỉ lambda không bắt được có thể được chuyển đổi thành con trỏ thành hàm. Tất nhiên, điều đó cũng bao gồm rất nhiều loại F không phải là lambda.

+0

Cho phép con trỏ hàm không phải lambda có thể vô hại hoặc có lợi.+1 – Potatoswatter