2013-10-01 20 views
5

Tôi đang cố gắng viết một hàm như std::for_each, ngoài việc sử dụng thông thường, cũng có thể mất std::function<bool (param)>. Giá trị trả về false có nghĩa là tôi muốn thoát khỏi vòng lặp. Mã dưới đây là những gì tôi đã nhận được cho đến nay.tham số lambda với giá trị trả về tùy chọn

Cuộc gọi thứ hai tới a.visit([&](int) -> void) không biên dịch khi đánh giá! Khách truy cập (i). Có thể làm công việc này hay tôi đang sủa cây sai?

Tôi đang sử dụng MSVC 2010 nhưng muốn mã nói chung tương thích với C++ 11.

#include <list> 
#include <string> 
#include <iostream> 

struct A 
{ 
    std::list<int> _lst; 

    template<typename _F> 
    void visit(_F visitor) 
    { 
     for(std::list<int>::const_iterator it = _lst.begin(), end = _lst.end() ; it != end ; it++) { 
      int i = *it; 
      if (std::is_void<decltype(visitor(i))>::value) { 
       visitor(i); 
      } else { 
       if (!visitor(i)) { // <----- error C2171: '!' : illegal on operands of type 'void' 
        break; 
       } 
      } 
     } 
    } 

}; 

int main(int argc, char* argv[]) 
{ 
    A a; 
    // populate a 
    for (int i = 0 ; i < 10 ; i++) { 
     a._lst.push_back(i); 
    } 

    a.visit([](int i) -> bool { 
     std::cout << i << std::endl; 
     return i < 5; 
    }); 

    a.visit([](int i) { 
     std::cout << i << std::endl; 
    }); 
} 
+0

Mã trên cả hai mặt của nhánh nếu cần phải chính xác và có thể biên dịch, vì vậy bạn không thể chọn dựa trên std :: is_void bên trong phần thân hàm. – goji

+0

Tại sao bạn sử dụng tên bắt đầu bằng dấu gạch dưới và một chữ cái viết hoa như '_F'? –

+0

Đó là quy ước tôi sử dụng cho các tham số mẫu. Tôi nghĩ tôi đã nhặt nó từ khi nhìn vào mã STL. – kylewm

Trả lời

6

Đây là cách tôi sẽ triển khai for_almost_each; Tôi là using namespace std cộng với bí danh loại cho mục đích dễ đọc.

#include <algorithm> 
#include <iterator> 
#include <functional> 

using namespace std; 

template<class Iter, class Func> 
Iter 
for_almost_each_impl(Iter begin, Iter end, Func func, std::true_type) 
{ 
    for (auto i = begin; i!=end; ++i) 
     if (!func(*i)) 
      return i; 
    return end; 
} 

template<class Iter, class Func> 
Iter 
for_almost_each_impl(Iter begin, Iter end, Func func, std::false_type) 
{ 
    for_each(begin, end, func); 
    return end; 
} 


template<class Iter, class Func> 
Iter for_almost_each(Iter begin, Iter end, Func func) 
{ 
    using Val = typename iterator_traits<Iter>::value_type; 
    using Res = typename result_of<Func(Val)>::type; 
    return for_almost_each_impl(begin, end, 
           func, 
           is_convertible<Res, bool>{}); 
} 

tôi đã sử dụng is_convertible, vì nó dường như có ý nghĩa hơn is_same.

+0

Cảm ơn rất nhiều, tôi đã chấp nhận câu trả lời của @ Troy vì đây là câu trả lời đầu tiên, nhưng tôi học được rất nhiều từ việc đọc của bạn! – kylewm

+0

Cũng lưu ý việc sử dụng 'result_of', hoạt động đúng cách độc lập với cách đối số được xây dựng; Câu trả lời của Troy chỉ hoạt động khi functor chấp nhận chữ '0'. – DanielKO

+0

@ kyle_wm: Bạn nên chọn câu trả lời hay nhất và có thể thay đổi ý định chính xác vì các câu trả lời sau có thể tốt hơn. IMO đây là một ví dụ mà câu trả lời thứ hai tốt hơn. – MSalters

-1

lambda này không trả về giá trị, đó là lý do tại sao bạn đang nhận được một lỗi mà "truy cập" đang trở lại khoảng trống:

a.visit([](int i) { 
    std::cout << i << std::endl; 
}); 

Bạn có thể làm việc này bằng cách viết lại như sau:

a.visit([](int i) -> bool { 
    std::cout << i << std::endl; 
    return true; 
}); 
+0

Điều đó thiếu điểm. Cả hai cuộc gọi sẽ hoạt động, mục tiêu là thay đổi 'lượt truy cập 'để làm cho nó hoạt động. – MSalters

4

Tiêu chuẩn của bạn :: is_void cần được thực hiện tại thời gian biên dịch và không thể thực hiện bên trong nội dung chức năng. Việc sử dụng chức năng quá tải này sẽ hoạt động:

#include <list> 
#include <string> 
#include <iostream> 
#include <type_traits> // missing header 

struct A 
{ 
    std::list<int> _lst; 

    // wrapper for bool returning visitor 
    template<typename _F, typename Iter> 
    bool do_visit(_F visitor, Iter it, std::true_type) 
    { 
     return visitor(*it); 
    } 

    // wrapper for non-bool returning visitor 
    template<typename _F, typename Iter> 
    bool do_visit(_F visitor, Iter it, std::false_type) 
    { 
     visitor(*it); 
     return true; 
    } 

    template<typename _F> 
    void visit(_F visitor) 
    { 
     for (auto it = _lst.begin(), end = _lst.end() ; it != end ; it++) { 
      // select correct visitor wrapper function using overloading 
      if (!do_visit(visitor, it, std::is_same<bool, decltype(visitor(0))>())) { 
       break; 
      } 
     } 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    A a; 
    // populate a 
    for (int i = 0 ; i < 10 ; i++) { 
     a._lst.push_back(i); 
    } 

    a.visit([](int i) -> bool { 
     std::cout << i << std::endl; 
     return i < 5; 
    }); 

    a.visit([](int i) { 
     std::cout << i << std::endl; 
    }); 
} 
+0

Đó chính là điều tôi đã hiểu lầm. Cảm ơn!! – kylewm

+0

Lưu ý rằng 'decltype (visitor (0))' sẽ không hoạt động khi '0' không phải là đối số hợp lệ cho' visitor'. 'std :: result_of' tồn tại vì điều đó. – DanielKO

+0

Nó đang truy cập danh sách 'int' không phải là danh sách các loại mẫu không xác định. – goji

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