Reputation: 10926
Given the following minimal example:
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <set>
#include <vector>
template<typename ContainerOut, typename X, typename Y, typename ContainerIn>
ContainerOut Map( const ContainerIn& xs, const std::function<Y( const X& )>& f )
{
ContainerOut ys;
std::transform( begin( xs ), end( xs ), std::inserter( ys, end( ys ) ), f );
return ys;
}
struct Foo {
Foo( int val ) : val_( val ) {}
int val_;
};
std::set<int> FooValsToIntSet( const std::list<Foo>& foos )
{
//Map<std::set<int>, Foo, int>
return Map( foos, []( const Foo& foo )
{
return foo.val_;
} );
}
int main()
{
std::list<Foo> foos = { 1, 2, 2, 3 };
std::set<int> vals = FooValsToIntSet( foos );
for ( auto& v : vals )
std::cout << v << std::endl;
}
The line
return Map( foos, []( const Foo& foo )
is not accepted by the compilers I tested.
It works if I write out the template arguments explicitly instead:
return Map<std::set<int>, Foo, int>( foos, []( const Foo& foo )
But I do not understand why this is necessary. Is there a way to avoid this verbosity?
Upvotes: 1
Views: 385
Reputation: 3977
Well, the compiler has no way of deducing the ContainerOut
type - the return type doesn't participate in type deduction. However, you could let the compiler deduce everything except the return type. Just as a side note, at least in this case, there is no reason to use std::function
- it's just adding unnecessary overhead.
This would be better:
template<typename ContainerOut, typename ContainerIn, typename F>
ContainerOut Map( const ContainerIn& xs, F&& f )
{
ContainerOut ys;
std::transform( begin( xs ), end( xs ), std::inserter( ys, end( ys ) ), f );
return ys;
}
and then you can call it as
return Map<std::set<int>>( foos, []( const Foo& foo )
{
return foo.val_;
} );
Upvotes: 7
Reputation: 6436
You don't seem to need the actual template parameters inside Map()
, so you can deduct the function object as a single parameter:
template<typename ContainerOut, typename ContainerIn, typename Function>
ContainerOut Map( const ContainerIn& xs, const Function& f )
{
...
}
This is also how STL algorithms taking a predicate do it.
Upvotes: 0