2013-12-12 16 views
9

Tôi muốn lưu bản thân mình một số cách gõ và do đó xác định một cái gì đó như thế này:C++ 11 - ràng buộc loại chức năng

using namespace std; 

vector<MyClass> vec; 

auto vecsort = bind(sort, vec.begin(), vec.end(), [] (MyClass const &a, MyClass const &b) { 
     // custom comparison function 
    }); 

vecsort(); // I want to use vecsort() a lot afterwards 

Đối với một số lý do này không biên dịch - tại sao?

Sử dụng tăng không phải là một tùy chọn.

Minimal dụ làm việc:

#include <vector> 
#include <utility> 
#include <algorithm> 
#include <functional> 

using namespace std; 

int main() { 

    vector<pair<int, int>> vec; 
    for (int i = 0; i < 10; i++) 
     vec.push_back(make_pair(10 - i, 0)); 

    auto vecsort = bind(sort, vec.begin(), vec.end(), [] (pair<int, int> const &a, pair<int, int> const &b) { 
      return a.first < b.first; 
     }); 

    vecsort(); 

} 

Lỗi:

error: no matching function for call to 'bind(<unresolved overloaded function type>, std::vector<std::pair<int, int> >::iterator, std::vector<std::pair<int, int> >::iterator, main()::__lambda0)'

+3

Có thông báo lỗi không. –

+0

@ R.MartinhoFernandes Có, và như mọi khi với C++ nó rất khó hiểu. Tôi đã bao gồm một ví dụ làm việc tối thiểu, mặc dù. – ryyst

+0

@ryyst: Cho chúng tôi biết thông báo lỗi. BTW ví dụ làm việc tối thiểu của bạn không hoạt động như nó thiếu bao gồm. –

Trả lời

11

Vấn đề là std::sort không phải là một đối tượng hàm. Nó là một mẫu chức năng. Cách đơn giản nhất để đối phó với vấn đề này là tạo ra một đối tượng wrapper đơn giản:

struct sorter { 
    template <typename RndIt, typename Cmp> 
    void operator()(RndIt begin, RndIt end, Cmp cmp) { 
     std::sort(begin, end, cmp); 
    } 
}; 

Bây giờ bạn có thể sử dụng

std::bind(sorter(), vec.begin(), vec.end(), [](...){ ... }); 
+0

Nếu chỉ những đối tượng đó không phải là một PITA để tạo ra ... – Xeo

+0

@ Xeo bạn nên đề xuất một cái gì đó cho một số tổ chức hoặc một cái gì đó mà có thể làm điều gì đó về điều đó ... – Yakk

+0

@ Yakk: Vâng, [có lẽ tôi nên.] (Https://dl.dropboxusercontent.com/u/14327987/functional_cpp.html);) – Xeo

7

Những người khác đã nêu lý do tại sao nó không biên dịch, nhưng hoạt động giải pháp thay thế này cho bạn? Điều này sử dụng một lambda khác, thay vì liên kết, để tạo ra hàm std ::.

#include <vector> 
#include <utility> 
#include <algorithm> 
#include <functional> 
#include <iostream> 

using namespace std; 

int main() { 

    vector<pair<int, int>> vec; 
    for (int i = 0; i < 10; i++) { 
     vec.push_back(make_pair(10 - i, 0)); 
    } 

    auto vecsort = [&vec] { 
     sort(vec.begin(), vec.end(), 
     [] (pair<int, int> const &a, pair<int, int> const &b) { 
      return a.first < b.first; 
     }); 
    }; 

    // vecsort will work as long as vec is in scope. 
    // vecsort will modify the original vector. 
    vecsort(); 
    for (auto i : vec) { 
     std::cout << '(' << i.first << ", " << i.second << ") "; 
    } 
    std::cout << endl; 

    vec.push_back(make_pair(-42, 0)); 
    vecsort(); 
    for (auto i : vec) { 
     std::cout << '(' << i.first << ", " << i.second << ") "; 
    } 
    std::cout << endl; 
} 

Output:

(1, 0) (2, 0) (3, 0) (4, 0) (5, 0) (6, 0) (7, 0) (8, 0) (9, 0) (10, 0) 
(-42, 0) (1, 0) (2, 0) (3, 0) (4, 0) (5, 0) (6, 0) (7, 0) (8, 0) (9, 0) (10, 0) 

Xem nó chạy ở đây: http://ideone.com/W2YQKW

+0

Có, điều này phù hợp với tôi và tôi thích nó. Cảm ơn! – ryyst

3

Dưới đây là một macro hữu ích cho vấn đề này. Những gì nó làm là tạo ra một vô danh struct có trường hợp đại diện cho tập hợp các quá tải gọi một tên hàm cụ thể (theo giá trị chuỗi) trong một ngữ cảnh cụ thể.

C++ thiếu chức năng như vậy đáng buồn. Nếu chỉ có ai đó đề xuất nó với ủy ban tiêu chuẩn hóa C++. Than ôi.

#define OVERLOAD_SET(FUNCTION_NAME) struct { template<typename... Args>\ 
    auto operator()(Args&&... args) const->\ 
    decltype(FUNCTION_NAME(std::forward<Args>(args)...))\ 
    { return (FUNCTION_NAME(std::forward<Args>(args)...)); } \ 
} 

Trong phạm vi toàn cầu:

OVERLOAD_SET(std::sort) sorter; 

Sau đó, vào thời điểm sử dụng:

std::bind(sorter, vec.begin(), vec.end(), [](...) {...}); 

Vấn đề là std::sort là một tập template (hoặc có thể của template s được chọn thông qua quá tải!) mà tạo ra các chức năng khi được gọi, không phải là một chức năng thực tế. Nó trông giống như một chức năng, nhưng nó không phải là. Và template bộ s và quá tải không thể được chuyển trực tiếp đến các chức năng khác. Ngoài ra, một cải tiến đối với macro OVERLOAD_SET ở trên có thể được thực hiện bằng cách thêm một template<typename R, typename... Args> operator R(*)(Args...)() const cho phép OVERLOAD_SET được đúc hoàn toàn với một con trỏ hàm cụ thể, nhưng điều này nằm ngoài phạm vi của vấn đề này.


Xeo đã đưa ra đề xuất như vậy.

+0

Lưu ý rằng C++ cấm các mẫu hàm thành viên cho các lớp địa phương, vì vậy điều này cần phải xảy ra ở phạm vi toàn cục. Và bạn không thể chỉ tạo nội dòng bằng hàm 'OVERLOAD_SET' vì bạn không thể tạo các kiểu như là một phần của một biểu thức. – Xeo

+0

@Xeo điểm. Đã xóa các thành phần chưa được kiểm tra. – Yakk

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