2011-12-12 55 views
5

Tôi có chương trình sau sử dụng ptr_fun với hàm lambda.ptr_fun với hàm lambda

#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <string> 
#include <cstring> 

using namespace std; 
int main() 
{ 
    string target="aa"; 
    vector<string> v1; 
    v1.push_back("aa"); 
    v1.push_back("bb"); 
    auto stringcasecmp=[](string lhs, string rhs)->int 
    { 
     return strcasecmp(lhs.c_str(), rhs.c_str()); 
    }; 

    auto pos = find_if(
     v1.begin(), v1.end(), 
     not1(bind2nd(ptr_fun(stringcasecmp), target)) 
     ); 

    if (pos != v1.end()) 
    cout << "The search for `" << target << "' was successful.\n" 
     "The next string is: `" << pos[1] << "'.\n"; 
} 

Tôi nhận được thông báo lỗi sau.

stackoverflow.cpp: In function ‘int main()’: 
stackoverflow.cpp:21:41: error: no matching function for call to ‘ptr_fun(main()::<lambda(std::string, std::string)>&)’ 
stackoverflow.cpp:22:6: error: unable to deduce ‘auto’ from ‘<expression error>’ 

Làm cách nào để sửa đổi mã (tối thiểu) để biên dịch?

+1

Chỉ cần một chút sidenote: Nếu bạn đang có kế hoạch về việc sử dụng một lambda như một trong những bạn có ở đây rất nhiều, có lẽ bạn xem xét chuyển các đối số dưới dạng tham chiếu. Tiết kiệm rất nhiều sao chép chuỗi. –

+0

Bạn có thể thấy rằng lambda 'stringcasecmp' của bạn là đệ quy! – quamrana

+0

@quamrana Tại sao nó đệ quy? – ggg

Trả lời

9

bind2nd (§D.9) và ptr_fun (§D.8.2.1) không được dùng nữa trong C++ 11. Bạn chỉ có thể viết một hàm lambda trong find_if:

auto pos = find_if(v1.begin(), v1.end(), 
        [&](const std::string& s) { 
         return !stringcasecmp(s, target); 
        }); 

ptr_fun(<lambda>) sẽ không làm việc, bởi vì ptr_fun được thiết kế cho C++ 03 để chuyển đổi một con trỏ hàm đến một đối tượng chức năng cho adapter khác. Một lambda đã là một đối tượng hàm, do đó, ptr_fun là không cần thiết.

bind2nd hy vọng đối tượng hàm xác định các thành viên second_argument_typeresult_type, điều này không đúng đối với lambda, vì vậy viết bind2nd(<lambda>, target) cũng không hoạt động. Nhưng trong C++ 11 có một sự thay thế chung mà hoạt động:

std::bind(stringcasecmp, std::placeholders::_1, target) 

Tuy nhiên, bind không trả lại C++ 03 kiểu đối tượng chức năng, mà not1 được mong đợi: nó đòi hỏi loại kết quả của bind để xác định thành viên argument_type không tồn tại. Do đó biểu thức cuối cùng

std::not1(std::bind(stringcasecmp, std::placeholders::_1, target)) 

sẽ sẽ hoạt động. Cách giải quyết đơn giản nhất là sử dụng một lambda khác mà tôi đã viết ở trên.

Ngoài ra, bạn có thể định nghĩa một negator generic:

template <typename Predicate> 
struct generic_negate 
{ 
    explicit generic_negate(Predicate pred) : _pred(pred) {} 

    template <typename... Args> 
    bool operator()(Args&&... args) 
    { 
     return !_pred(std::forward<Args>(args)...); 
    } 
private: 
    Predicate _pred; 
}; 

template <class Predicate> 
generic_negate<Predicate> not_(Predicate pred) 
{ 
    return generic_negate<Predicate>(pred); 
} 

.... 

auto pos = find_if(v1.begin(), v1.end(), not_(bind(stringcasecmp, _1, target))); 

Ví dụ: http://ideone.com/6dktf

+0

Cảm ơn. Tôi nghĩ rằng nó là khá lẻ mà bind2nd là không được chấp nhận, nhưng c + + 11 liên kết không làm việc với not1. – ggg

+0

"*' ptr_fun () 'sẽ không hoạt động, bởi vì' ptr_fun' được thiết kế cho C++ 03 để chuyển đổi một con trỏ hàm thành đối tượng hàm cho các bộ điều hợp khác. * "Tại sao nó không hoạt động, lambdas được ngầm chuyển đổi để con trỏ chức năng? – ildjarn

+1

@ildjarn: Tôi không nghĩ một nhà điều hành chuyển đổi sẽ tham gia vào việc khấu trừ đối số mẫu. – kennytm

0

Hãy thử pointer_to_binary_function<string,string,int>(stringcasecmp) thay vì ptr_fun(stringcasecmp)?

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