2010-07-23 37 views
17

Hãy nhìn vào C++ 0x lambda mã liên quan sau đây:C++ 0x lambda, làm thế nào tôi có thể chuyển như một tham số?

typedef uint64_t (*WEIGHT_FUNC)(void* param); 
typedef std::map<std::string, WEIGHT_FUNC> CallbackTable; 

CallbackTable table; 
table["rand_weight"] = [](void* param) -> uint64_t 
{ 
    return (rand() % 100 + 1); 
}; 

Tôi đã nhận ra lỗi (trong Visual Studio 2010) rằng lambda không thể được chuyển đổi sang các loại WEIGHT_FUNC. Tôi cũng biết câu trả lời: sử dụng std::function object:

typedef std::function<uint64_t (void*)> WEIGHT_FUNC; 

Tuy nhiên, tôi cũng muốn biết làm thế nào tôi có thể nhận được các loại lambda KHÔNG sử dụng std::function. Loại đó nên là gì?

+1

'tự động'? _______ – kennytm

+2

tự động sẽ chỉ hữu ích để tự động xác định loại, nó không phải là một loại biến thể, nó không thể là một tham số. – Klaim

+2

Bạn đang sử dụng trình biên dịch nào? Dường như trình biên dịch của bạn là không chuẩn trong trường hợp lambda's, họ sẽ có thể chuyển đổi hoàn toàn thành con trỏ hàm (trong trường hợp như thế này.) – GManNickG

Trả lời

20

Việc chuyển đổi chức năng con trỏ là tương đối mới: Nó đã được giới thiệu với N3043 vào ngày 15, 2010.

Trong khi ví dụ GCC 4.5 thực hiện nó, Visual Studio 10 đã được phát hành vào ngày 12 tháng 4 năm 2010 và do đó chỉ không thực hiện nó trong thời gian. Như James đã chỉ ra, điều này will be fixed trong các bản phát hành trong tương lai.

Hiện tại, bạn phải sử dụng một trong các giải pháp thay thế được cung cấp tại đây.

Về mặt kỹ thuật giống như cách giải quyết sau đây sẽ làm việc, nhưng không có variadic các mẫu không có niềm vui của nó để khái quát nó (Boost.PP để giải cứu ...) và không có mạng lưới an toàn chống lại qua chụp lambdas trong:

typedef uint64_t (*WeightFunc)(void* param); 

template<class Func> WeightFunc make_function_pointer(Func& f) { 
    return lambda_wrapper<Func>::get_function_pointer(f); 
} 

template<class F> class lambda_wrapper { 
    static F* func_; 
    static uint64_t func(void* p) { return (*func_)(p); }  
    friend WeightFunc make_function_pointer<>(F& f);  
    static WeightFunc get_function_pointer(F& f) { 
     if (!func_) func_ = new F(f); 
     return func; 
    } 
}; 

template<class F> F* lambda_wrapper<F>::func_ = 0; 

// ... 
WeightFunc fp = make_function_pointer([](void* param) -> uint64_t { return 0; }); 
+8

Điều đáng nói là chuyển đổi sang con trỏ hàm chỉ dành cho chức năng lambda không trạng thái, chúng không thể nắm bắt phạm vi từ vựng. –

+0

Việc chuyển đổi sang con trỏ hàm dường như không hoạt động với g ++ 4.5 trong mã mẫu (http://tinyurl.com/3y6hkyq) – rafak

+0

Xem http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45080 cho điều đó . –

-1

Hãy thử với (không kiểm tra):

#include <function> 

typedef std::function< int64_t (void*) > weight_func; 
typedef std::map<std::string, weight_func > CallbackTable; 

Tôi không nghĩ có bất kỳ cách nào khác để làm điều này hơn để sử dụng std :: chức năng hoặc tương đương.

+0

Cảm ơn bạn đã sửa chữa sbi – Klaim

+3

Không sử dụng 'std :: function ', sử dụng 'std :: function '. –

+0

Phải! Cố định, cảm ơn! – Klaim

1

Nếu bạn thực sự nhấn mạnh vào không sử dụng function<> thì có thể bạn có thể sử dụng decltype:

typedef decltype([](void*)->uint_64{return 0;}) my_lambda_type; 

Tôi thực sự tôi không khuyến khích điều này mặc dù kể từ khi bạn đang quyết liệt hạn chế bản thân và tôi thậm chí không biết nếu hai lambda với cùng chữ ký được đảm bảo là cùng loại.

+0

Có đảm bảo rằng loại được tạo sẽ giống nhau nếu bạn viết đúng typedef ở đâu đó khác? Tôi không nghĩ bạn nên cho rằng kiểu chữ phụ thuộc vào chữ ký ... nhưng có lẽ tôi sai. – Klaim

+0

Không hoạt động trong GCC. –

+1

Câu trả lời cũ, tôi biết, nhưng biểu thức lambda không thể xuất hiện trong một ngữ cảnh không được đánh giá. (Tôi nghĩ lý do là thứ bạn đưa ra: vì mỗi biểu thức lambda là một kiểu duy nhất, không xác định, bạn không được đảm bảo bất kỳ câu trả lời có ý nghĩa cụ thể nào trong một ngữ cảnh không được đánh giá.) – GManNickG

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