函数模板中返回类型的模板实参演绎

template argument deduction of return type in function template

本文关键字:实参 演绎 返回类型 函数模板      更新时间:2023-10-16

给出以下最小示例:

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

不被我测试的编译器接受。

如果我显式地写出模板参数,它就可以工作了:

return Map<std::set<int>, Foo, int>( foos, []( const Foo& foo )

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

嗯,编译器没有办法推断出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_;
} );

您似乎不需要 Map()内部的实际模板参数,因此您可以将函数对象作为单个参数扣除:

template<typename ContainerOut, typename ContainerIn, typename Function>
ContainerOut Map( const ContainerIn& xs, const Function& f )
{
    ...
}

这也是STL算法获取谓词的方式