2013-08-07 44 views
5

Thông thường, để kiểm tra nếu một con trỏ trỏ đến chức năng, sử dụng std::is_function là đủ.Làm thế nào để kiểm tra lambda trong C++ 11

Tuy nhiên, nó không thể hoạt động với lambda. Kể từ lambda là một đối tượng với operator().

Bây giờ tôi phải sử dụng cả hai is_functionis_object để kiểm tra xem một hoạt động giống như chức năng, như sau:

std::is_function<decltype(f)>::value || std::is_object<decltype(f)>::value

Vì vậy, tôi tự hỏi nếu có một cách tốt hơn để kiểm tra xem ai là lambda hay không?

EDIT:

đang liên quan:

template<typename Func> 
void deferJob(Func f, int ms=2000) 
{ 
    if(! std::is_function<decltype(f)>::value 
      && ! std::is_object<decltype(f)>::value){ 
     qDebug()<<"Not function!"; 
     return; 
    } 
    QTimer* t = new QTimer; 
    t->setSingleShot(true); 
    QObject::connect(t, &QTimer::timeout, 
      [&f, t](){ 
     qDebug()<<"deferJob"; 
     f(); 
     t->deleteLater(); 
    }); 
    t->start(ms); 
} 

EDIT2:

tương tự câu hỏi: C++ metafunction to determine whether a type is callable

+0

http://www.cplusplus.com/reference/functional/function/function/ chỉ gán một lambda đến một thể hiện của 'std :: function'; vấn đề chính là lambda là vô danh, vì vậy bạn cần phải đưa ra một "tên" cho nó. – user2485710

+4

Một đối tượng lambda chỉ là một hàm. Làm thế nào để bạn hiện đang xử lý các functors? – cdhowie

+0

@ user2485710 Tuy nhiên, nó không phải là một cách để kiểm tra. nó chỉ làm cho trình biên dịch phàn nàn về nó. – liuyanghejerry

Trả lời

5

Vì vậy, đây là một vài suy nghĩ có thể có hoặc không có thể hữu ích.

  • Để tạo một type_trait mà làm việc cho functors, lambdas và chức năng truyền thống, tôi nghĩ rằng tôi sẽ nhìn vào thấy nếu đối số mẫu là chuyển đổi thành một std::function<void()>. Tôi nghĩ rằng sẽ bao gồm hầu hết các căn cứ một cách rõ ràng.

  • Như chúng tôi đã đề cập trong các nhận xét, bạn không thể kiểm tra đối số mẫu như cách bạn đang làm. Các f() sau này trong chức năng sẽ gây ra một lỗi biên dịch, và do đó bạn sẽ không bao giờ có cơ hội để xem lỗi thời gian chạy.

  • Bạn có thể thử làm điều gì đó với std::enable_if. Bạn cần phải tạo chuyên môn mẫu để SFINAE có thể hoạt động để chọn triển khai chính xác. Điều này sẽ sử dụng type_trait mà tôi đã đề cập trong bullet 1.

  • Nếu bạn đã làm điều này, bạn có thể thực hiện mẫu khác là static_assert để tạo thông báo lỗi "tốt hơn".

  • Điều đó đang được nói, các thông báo lỗi trình biên dịch không phải là điều xấu ngay từ đầu. (Ít nhất là trong clang và gcc. Tôi đã không nhìn như msvc).


này không giúp bạn có được một thông báo lỗi rất lớn, nhưng nó giúp bạn có một khác nhau một:

#include <cassert> 
#include <functional> 
#include <type_traits> 

template <typename Func> 
typename std::enable_if<std::is_convertible<Func, std::function<void()>>::value>::type 
deferJob(Func f, int ms=2000) { 
} 

void normal_function() {} 

int main() { 
    deferJob([]() {});   // works 
    deferJob(&normal_function); // works 
    deferJob(3);    // compile time error 
} 

Trong Clang, tôi nhận được một lỗi mà trông giống như:

foo.cc:15:2: error: no matching function for call to 'deferJob' 
     deferJob(3);    // compile time error 
     ^~~~~~~~ 
foo.cc:6:25: note: candidate template ignored: disabled by 'enable_if' [with Func = int] 
typename std::enable_if<std::is_convertible<Func, std::function<void()>>::value>::type 

Trong GCC, tôi nhận được lỗi có dạng:

foo.cc: In function ‘int main()’: 
foo.cc:15:12: error: no matching function for call to ‘deferJob(int)’ 
    deferJob(3);    // compile time error 
      ^
foo.cc:15:12: note: candidate is: 
foo.cc:7:1: note: template<class Func> typename std::enable_if<std::is_convertible<Func, std::function<void()> >::value>::type deferJob(Func, int) 
deferJob(Func f, int ms=2000) { 
^ 
foo.cc:7:1: note: template argument deduction/substitution failed: 
foo.cc: In substitution of ‘template<class Func> typename std::enable_if<std::is_convertible<Func, std::function<void()> >::value>::type deferJob(Func, int) [with Func = int]’: 
foo.cc:15:12: required from here 
foo.cc:7:1: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’ 

Chúng ta có thể đi một bước xa hơn (mặc dù làm nó theo cách này làm cho nó khó có thể mở rộng hơn nữa) và thêm một chức năng bổ sung:

template <typename Func> 
typename std::enable_if<not std::is_convertible<Func, std::function<void()>>::value>::type 
deferJob(Func f, int ms=2000) { 
    static_assert(false, "You should pass a function"); 
} 

Điều này gây ra kêu vang báo cáo (tại thời gian biên dịch):

foo.cc: In function ‘typename std::enable_if<(! std::is_convertible<Func, std::function<void()> >::value)>::type deferJob(Func, int)’: 
foo.cc:14:2: error: static assertion failed: You should pass a function 
    static_assert(false, "You should pass a function"); 

Nhưng thật đáng buồn, nó không đưa ra một chồng dấu vết, vì vậy tôi sẽ tìm thấy điều này xa ít hữu ích hơn bất kỳ thông báo trước đó.


Và cuối cùng, chúng tôi cũng có thể thay thế mà khẳng định tĩnh với thông điệp thời gian chạy của bạn:

template <typename Func> 
typename std::enable_if<not std::is_convertible<Func, std::function<void()>>::value>::type 
deferJob(Func f, int ms=2000) { 
    qDebug() << "Not function!"; 
} 
+0

Cảm ơn, đây là điều tôi muốn ban đầu. Mặc dù có vẻ như biên dịch lỗi rõ ràng là tốt hơn. – liuyanghejerry

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