给出以下最小例子:
#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;
}
该行
return Map( foos, []( const Foo& foo )
编译器tested不接受。
如果我明确地写出模板参数,它就可以了:
return Map<std::set<int>, Foo, int>( foos, []( const Foo& foo )
但我不明白为什么这是必要的。有没有办法避免这种冗长?
答案 0 :(得分:7)
好吧,编译器无法推断出ContainerOut
类型 - 返回类型不参与类型推导。但是,您可以让编译器推断除返回类型之外的所有内容。正如旁注,至少在这种情况下,没有理由使用std::function
- 它只是增加了不必要的开销。
这会更好:
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;
}
然后你可以把它称为
return Map<std::set<int>>( foos, []( const Foo& foo )
{
return foo.val_;
} );
答案 1 :(得分:0)
您似乎需要 Map()
内的实际模板参数,因此您可以将函数对象作为单个参数扣除:
template<typename ContainerOut, typename ContainerIn, typename Function>
ContainerOut Map( const ContainerIn& xs, const Function& f )
{
...
}
这也是采用谓词的STL算法如何做到的。