2011-07-04 47 views
7

Tôi tình cờ tìm ra một vấn đề biên dịch lạ. Tôi muốn xử lý danh sách các chuỗi, sử dụng std::for_each. Mã đơn giản sau đây minh họa sự cố:std :: for_each bỏ qua đối số hàm mặc định

# include <list> 
# include <string> 
# include <algorithm> 

using namespace std ; 

void f(wstring & str) 
{ 
    // process str here 
} 

void g(wstring & str, int dummy = 0) 
{ 
    // process str here, same as f, just added a second default dummy argument 
} 

int main(int, char*[]) 
{ 
    list<wstring> text ; 

    text.push_back(L"foo") ; 
    text.push_back(L"bar") ; 

    for_each(text.begin(), text.end(), f) ; // OK, fine :) 
    for_each(text.begin(), text.end(), g) ; // Compilation error, complains about 
        // g taking 2 arguments, but called within std::for_each 
        // with only one argument. 

    // ... 
    return 0 ; 
}  

Tôi đã thử nghiệm bằng cách sử dụng MinGW 4.5.2 và MSVC10, cả hai đều báo cáo cùng một thông báo lỗi. Ban đầu, tôi muốn sử dụng boost::algorithm::trim làm chức năng xử lý được chuyển đến std::for_each nhưng tôi nhận thấy rằng cần hai đối số, bắt buộc đầu tiên (chuỗi cần xử lý) và thứ hai là tùy chọn (ngôn ngữ cung cấp định nghĩa cho ký tự khoảng trắng) .

Có cách nào để giữ cho mọi thứ sạch sẽ khi sử dụng std::for_each (và các thuật toán chuẩn khác) khi có chức năng hoặc phương pháp với đối số mặc định không? Tôi tìm thấy một cách để làm cho nó hoạt động, nhưng nó là không rõ ràng và dễ hiểu, do đó, một vòng lặp for bắt đầu có vẻ dễ dàng hơn ...

# include <list>  
# include <string> 
# include <algorithm> 
# include <boost/bind.hpp> 
# include <boost/algorithm/string.hpp> 

using namespace std ; 
using namespace boost ; 

// ... somewhere inside main 
list<wstring> text ; 
for_each(text.begin(), text.end(), bind(algorithm::trim<wstring>, _1, locale()) ; 
// One must deal with default arguments ... 
// for_each(text.begin(), text.end(), algorithm::trim<wstring>) would be a real pleasure 

Nhờ sự giúp đỡ!

Note: Tôi chỉ mới bắt đầu học tiếng Anh, xin lỗi cho những sai lầm :)

+0

Tôi nghĩ rằng nó chỉ đơn giản là không làm việc theo cách này cho các functors. Xóa đối số giả. –

+0

Đối số giả tôi đã thêm vào 'g' là để chứng minh hành vi kỳ lạ của' std :: for_each'. Gọi 'g' với một số' wstring str' như 'g (str)' hoạt động như một nét duyên dáng, nhưng không phải bên trong 'std :: for_each'. Trong trường hợp của tôi, sử dụng thuật toán 'boost :: :: trim' trực tiếp như hàm functor là không thể nếu không có thủ thuật, vì đối số thứ hai của nó là tùy chọn (một std :: locale) – overcoder

+2

@Overcoder: đó là vì' g (str) 'ngay lập tức trở thành 'g (str, 0)' - đối số mặc định chỉ là đường tạo mã. –

Trả lời

6

Mặc định tranh luận chỉ là một công cụ mã thế hệ và không nằm trong chữ ký chức năng, vì vậy bạn có thể không thực sự có được xung quanh đó. Bạn có thể bọc hàm của bạn trong một đối tượng hàm, nhưng đó chính xác là những gì bind đã làm cho bạn.

Tuy nhiên, trong C++ 0x bạn thuận tiện có thể lưu trữ kết quả (và sử dụng std::bind) để có thể làm cho đoạn code một chút dễ đọc hơn:

auto trimmer = std::bind(boost::algorithm::trim<std::wstring>, std::placeholders::_1, std::locale()); 

std::for_each(text.begin(), text.end(), trimmer); 

(Lý do bạn không muốn làm điều đó trong C++ 98/03 là kiểu trả về của bind là một cái gì đó khá khó coi, và bạn sẽ không làm bất cứ ai bằng cách đánh vần nó.)

Hoặc, một lần nữa trong C++ 0x, bạn có thể sử dụng lambda:

std::for_each(text.begin(), text.end(), [](std::wstring & s){ boost::algorithm::trim<std::wstring>(s); }); 
+2

Ngoài ra, nếu bạn bị mắc kẹt với tiêu chuẩn hiện tại, hãy xem bind2nd (thực sự nó có một số yêu cầu cho functors - g của bạn nên được cấu trúc kế thừa từ binary_function) – cybevnm

+0

@vnm: vâng, điểm tốt, một phụ thuộc ít hơn: ' std :: for_each (..., ..., std :: bind2nd (tăng :: thuật toán :: cắt , std :: locale())); '. –

+1

Cảm ơn! Tôi sẽ xem nếu tôi có thể kích hoạt C++ 0x cho dự án hiện tại của tôi. Lambdas có vẻ thuận tiện hơn. – overcoder

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