Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lambda with templates

I am currently doing some exercises with templated functions. I had the task to write a implementation of the transform algorithm. I did it like the following and it works:

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;
}

As with the normal transform I have to call the predicate with an explicit type like

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

Now, I stumbled upon the C++11 Lambdas and wanted to call my function like this:

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

With that I do get a compiler error that the type cant be deduced. This is the thing I dont understand as I am defining the T type in my lambda actually twice.

I did also check back the original transform function, with which it is working. I then checked the implementation of that one and it is obviously implemented with a template class for the whole function. Is that the correct way for implementing predicates with templates?

like image 982
Stephan Dollberg Avatar asked Oct 06 '11 09:10

Stephan Dollberg


3 Answers

The predicate is normally a simple template argument:

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

This will accept pointers to function, lambdas and function objects.

like image 164
visitor Avatar answered Sep 22 '22 20:09

visitor


T p(const T&) is the type of a function which takes a T by reference. Your lambda takes its argument by value.

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

This should work. A lambda which does not perform any capturing is convertible to an ordinary function.

like image 39
spraff Avatar answered Sep 24 '22 20:09

spraff


it is obviously implemented with a template class for the whole function

Slight aside for proper terminology: std::transform is a function template, not a function. More importantly, in a declaration of the style

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

the template parameters InputIterator, OutputIterator and Functor are not required to be class types. Consider this example:

// function declaration
int increment(int);

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

Then InputIterator and OutputIterator are deduced to be int* and Functor is int(*)(int), none of which is a class type -- much less a template class, but I digress. And in fact, transform could just as well be declared

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

where the keyword typename is a bit more clear on the nature of the template parameters: they're types, of any nature.

like image 44
Luc Danton Avatar answered Sep 26 '22 20:09

Luc Danton