假设,我想在C ++中实现通用的高阶Map
函数。 Map
应该使用容器和转换函数并返回相同类型的容器,但可能包含不同类型的项目。
我们以vector
为例:
template <typename InT, typename OutT, typename Tr>
vector<OutT> Map(vector<InT> cont, Tr tr)
{
OutCont out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++ot)
{
*oit = tr(*it);
}
}
我想这样使用:
vector<int> v(10);
std::iota(v.begin(), v.end(), 0);
auto x = Map(v, [](int x) -> int {return x * 2;});
这在VC ++ 2012中失败,给我以下错误:
error C2783: 'std::vector<OutT> Map(std::vector<_Ty>,Tr)' : could not deduce template argument for 'OutT'
在我看来,编译器具有所有必要的信息,因为我在lambda中明确定义了返回类型。有办法解决这个问题吗?
以上示例使用vector
。有没有办法使用泛型类型,以便输入和输出类型相同?例如,如果我有一个定义为vector<string>
的输入容器和转换函数tr(string a) -> int
,那么我的目标是让编译器找出输出类型为vector<int>
。这是我想要实现的伪代码:
template <typename Cont<InT>, typename Cont<OutT>, typename Tr<InT, OutT>>
Cont<OutT> Map(Cont<InT> cont, Tr<InT, OutT> tr)
{
// Implementation
}
答案 0 :(得分:4)
您可以写下类似的内容:
template <typename InT, typename Tr>
auto Map(std::vector<InT> cont, Tr tr) -> std::vector<decltype(tr(cont[0]))>
{
std::vector<decltype(tr(cont[0]))> out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit)
{
*oit = tr(*it);
}
return out;
}
推断出类型。
[编辑] 对于具有更多容器的更通用的函数:
template <template<typename, typename...> class Container, typename InT, typename Tr, typename... Args>
auto Map(const Container<InT, Args...>& cont, Tr tr) -> Container<decltype(tr(cont[0])), Args...>
{
Container<decltype(tr(cont[0])), Args...> out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit)
{
*oit = tr(*it);
}
return out;
}
请注意所需的typename...
,因为std::vector
也可以使用分配器