2012-06-21 27 views
6

Có thể sử dụng đối số kiểu mẫu từ một hàm mẫu xung quanh trong một hàm ẩn danh cục bộ không? Tôi khá chắc chắn tôi không thể khai báo một mẫu lambda ...Làm thế nào để sử dụng đối số kiểu mẫu trong lambda?

Ví dụ làm thế nào tôi sẽ đi về làm một cái gì đó như thế này:

template <typename T> 
void TrimString(std::basic_string<T>& str, const std::locale& loc = std::locale()) 
{ 
    // std::isspace as lambda unary predicate? 
    auto fn = [&loc](T c){ return std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); }; 
    // trim right 
    str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(fn)).base(), str.end()); 
    // trim left 
    str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(fn))); 
} 

Hiện này tạo ra các lỗi sau:

error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>' 

Có ý nghĩa khi lambda không có đầu mối về đối số T từ hàm mẫu lân cận.

Tôi sử dụng VS2010 và gcc 4.7 nhưng tôi không muốn sử dụng tăng.

Bất kỳ ý tưởng nào?

Chỉnh sửa: Dường như tôi đã sai khi giả định rằng vấn đề là chính đối số mẫu. Thay vào đó là việc sử dụng std::not1 được biên dịch với hàm lambda. Đây là kết quả lỗi chi tiết hơn:

error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>' 
: see declaration of '`anonymous-namespace'::<lambda0>' 
: see reference to class template instantiation 'std::unary_negate<_Fn1>' being compiled 
      with 
      [ 
       _Fn1=`anonymous-namespace'::<lambda0> 
      ] 
: see reference to function template instantiation 'void TrimString<char>(std::basic_string<_Elem,_Traits,_Ax> &,const std::locale &)' being compiled 
      with 
      [ 
       _Elem=char, 
       _Traits=std::char_traits<char>, 
       _Ax=std::allocator<char> 
      ] 

Bạn có cần tuyên bố rõ ràng loại đối số nếu đó là loại hàm không? Tôi không chắc chắn những gì tôi đang làm sai vẫn ...

Đáp:

Lựa chọn 1: Nếu tôi không sử dụng std::not1 và thay vào đó phủ nhận giá trị trả về trong lambda tôi nhận được cùng một hành vi không có vấn đề.

auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); }; 

Lựa chọn 2: Kể từ khi lambda không dài tương đương với cách std::isspace sẽ hành xử như một vị unary một đối tượng hàm constructor dàn diễn viên cũng thực hiện các trick.

str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::function<bool(T)>(fn))).base(), str.end()); 
+0

BTW, thông báo lỗi dường như chỉ ra rằng sự cố nằm ở một nơi khác, cụ thể với lambda được khai báo ở phạm vi * không gian tên *. – Nawaz

+1

Đúc 'fn' như thế này' std :: not1 (std :: function (fn)) 'cũng hoạt động. –

Trả lời

6

Bạn chắc chắn nhất có thể sử dụng T làm loại tham số của biểu thức lambda.Các chương trình sau biên dịch tiền phạt GCC 4.5.1:

include <iostream> 

template<typename T> 
void f(T arg) 
{ 
    auto print = [](T a) { std::cout << a << std::endl; }; 
    print(arg); 
} 

int main() { 
     f(8899); 
     f("Nawaz"); 
     return 0; 
} 

Xem mình: http://ideone.com/l32Z6

BTW, thông báo lỗi dường như chỉ ra rằng vấn đề nằm ở một nơi khác, đặc biệt là với một lambda tuyên bố tại namespace phạm vi:

error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>'


Sau EDIT của bạn, tất cả tôi có thể nói là dont rằng sử dụng std::not1 sau đó. Trong thực tế, bạn thậm chí không cần nó. Bạn có thể sử dụng return !whatever-expression trong bản thân lambda.

+0

Hmm ... do đó, lỗi của OP không phải là từ đối số lambda? – Jason

+0

@ Jason: Đó là những gì nó có vẻ là. – Nawaz

+0

Doh! Tôi sẽ cập nhật câu hỏi. – AJG85

2

Sửa: Như @Nawaz chỉ ra, lỗi của bạn phải được đến hình thức ở một nơi khác ... những gì tôi mô tả dưới đây là quá mức cần thiết ...

Sử dụng decltype, bạn có thể làm điều gì đó như sau:

template <typename T> 
void TrimString(std::basic_string<T>& str, 
       const std::locale& loc = std::locale(), 
       T arg = T()) 
{ 
    auto fn = [&loc](decltype(arg) c){ return std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); }; 

    //...rest of your code 
} 

này được sử dụng (hoặc lạm dụng) thực tế là sự biểu hiện decltype(arg) đánh giá để loại arg , trong trường hợp này là loại T.

+0

Tại sao sử dụng 'decltype' khi' T' chỉ hoạt động tốt? Anh ta cũng phải làm điều gì đó khác. – Nawaz

+0

Tôi đã giả định lỗi của mình đến từ những gì anh ta nói, đó là việc sử dụng 'T' hơn là một loại đối số đã biết ... rõ ràng là bài viết của bạn cho thấy không có vấn đề gì với ... – Jason

+0

Nếu tôi nắm bắt' arg' và sử dụng 'decltype' tôi nhận được cùng một lỗi. Rõ ràng là nếu tôi không nắm bắt nó thì nó phàn nàn về việc chụp ảnh ngụ ý hoặc không có chế độ chụp mặc định. Điều này có thể được dọc theo đường bên phải mặc dù nó không hoạt động ... hoặc MSVC bị hỏng nếu điều này sẽ làm việc. – AJG85

9

Sự cố không được gây ra bằng cách sử dụng thông số mẫu bên trong lambda, vì tham số đã được giải quyết thành loại tại thời điểm lambda được tạo.

Vấn đề là lambda bạn xác định không thể được kết hợp với std::not1, yêu cầu, làm đối số, một std::unary_function<argument_type,return_type>.

Cách đơn giản nhất để giải quyết vấn đề là không sử dụng std::not1, và thay vào đó phủ nhận sự truyền giáo ngay trong biểu thức lambda:

auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space,c); }; 

Mã hoàn chỉnh biên dịch và làm việc với GCC 4.7.0 sau đó trở thành:

#include <string> 
#include <algorithm> 
#include <locale> 
#include <iostream> 

template <typename T> 
void TrimString(std::basic_string<T>& str, const std::locale& loc = std::locale()) 
{ 
    auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space,c); }; 

    str.erase(std::find_if(str.rbegin(), str.rend(),fn).base(), str.end()); 
    str.erase(str.begin(), std::find_if(str.begin(), str.end(), fn)); 
} 

int main() { 
    std::basic_string<char> s(" hello "); 
    TrimString(s); 
    std::cout << s << std::endl; 
    return 0; 
} 

này kết quả đầu ra

hello 

như expe cted.

+0

Yup, chỉ đến kết luận này bản thân mình bây giờ mà tôi đã nhìn vào vấn đề thực tế! – AJG85

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