2011-10-06 26 views
5

Tôi hiện đang thực hiện một số bài tập có chức năng khuôn mẫu. Tôi có nhiệm vụ viết một thuật toán chuyển đổi. tôi đã làm nó như sau và nó hoạt động:lambda với các mẫu

template <class in, class out, class T> 
out stransform(in b, in e, out d, T p(const T&)) { 
    while (b != e) 
     *d++ = p(*b++); 
    return d; 
} 

Như với bình thường chuyển đổi tôi phải gọi vị với một loại rõ ràng như

stransform(begin(vec1), end(vec1), back_inserter(vec2), predi<double>); 

Bây giờ, tôi stumbled khi C++ 11 Lambdas và muốn gọi chức năng của tôi như thế này:

stransform(begin(vec1), end(vec1), back_inserter(vec2), [] (double x) ->double {return x * 10;}); 

Với điều đó tôi nhận được lỗi trình biên dịch mà loại không thể suy luận được. Đây là điều tôi không hiểu vì tôi đang xác định loại T trong lambda của tôi thực sự hai lần.

Tôi cũng đã kiểm tra lại chức năng biến đổi ban đầu, mà nó đang hoạt động. Sau đó tôi đã kiểm tra implementation của cái đó và nó rõ ràng được triển khai với một lớp mẫu cho toàn bộ hàm. Đó có phải là cách chính xác để triển khai các biến vị ngữ với các mẫu không?

Trả lời

13

Các vị ngữ thường là một mẫu tranh luận đơn giản:

template <class in, class out, class UnaryPredicate> 
out stransform(in b, in e, out d, UnaryPredicate p); 

này sẽ chấp nhận gợi ý để hoạt động, lambdas và các đối tượng chức năng.

+0

Tôi đã nghĩ như vậy sau khi đọc triển khai biến đổi, điều đó cũng giúp bạn dễ dàng hơn rất nhiều. Tôi vẫn tự hỏi tại sao tôi không làm việc trong trường hợp khác. – inf

+5

@ bamboon Tôi đoán vì lambda không có chức năng nhưng là một đối tượng hàm, vì nó cũng có thể giữ trạng thái (nó là một đóng và không chỉ là một hàm). –

+1

Lưu ý rằng một lambda mà không thực hiện bất kỳ bắt được chuyển đổi thành một hàm bình thường (con trỏ). – spraff

2

T p(const T&) là loại hàm thực hiện Tbằng cách tham chiếu. Lambda của bạn lấy đối số của nó bằng giá trị.

stransform (
    begin (vec1), 
    end (vec1), 
    back_inserter (vec2), 
    [] (const double & x) -> double { 
     return x * 10; 
    }); 

Điều này sẽ hiệu quả. Một lambda mà không thực hiện bất kỳ bắt được chuyển đổi thành một chức năng bình thường.

+1

nhưng tại sao dựa vào một chuyển đổi không cần thiết cho con trỏ hàm, khi bạn chỉ có thể xác định lại hàm functor để làm việc với các hàm con cũng như các con trỏ hàm? – jalf

+0

không hoạt động đối với tôi (sử dụng msvc2011). – inf

+0

@jalf Định nghĩa lại hàm functor là một giải pháp tốt hơn, tôi đồng ý. Nếu vấn đề này xuất hiện với mã thư viện không thay đổi thì chuyển đổi có thể hoạt động. – spraff

2

nó rõ ràng được thực hiện với một lớp mẫu cho toàn bộ chức năng

nhẹ dành cho các thuật ngữ thích hợp: std::transform là một chức năng mẫu, không phải là một chức năng. Quan trọng hơn, trong một tuyên bố của phong cách

template<class InputIterator, class OutputIterator, class Functor> 
OutputIterator 
transform(InputIterator begin, InputIterator end, OutputIterator out, Functor f); 

mẫu thông số InputIterator, OutputIteratorFunctor không cần phải được loại lớp. Hãy xem xét ví dụ sau:

// function declaration 
int increment(int); 

int array[] = { 0, 1, 2, 3, 4 }; 
transform(std::begin(array), std::end(array), std::begin(array), increment); 

Sau đó InputIteratorOutputIterator được suy luận là int*Functorint(*)(int), không ai trong số đó là một loại lớp - ít hơn nhiều một lớp mẫu, nhưng tôi lạc đề. Và trên thực tế, transform thể chỉ cũng được khai báo

template<typename InputIterator, typename OutputIterator, typename Functor> 
OutputIterator 
transform(InputIterator begin, InputIterator end, OutputIterator out, Functor f); 

nơi từ khóa typename là rõ ràng hơn một chút về bản chất của các thông số mẫu: chúng là hai loại, của bất kỳ thiên nhiên.

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