函数模板

时间:2015-10-12 14:29:14

标签: c++ c++11

给出以下最小例子:

#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 )

但我不明白为什么这是必要的。有没有办法避免这种冗长?

2 个答案:

答案 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算法如何做到的。