【问题标题】:Constraints on template types模板类型的约束
【发布时间】:2013-10-24 12:58:29
【问题描述】:

假设,我想在 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&lt;string&gt; 的输入容器和转换函数tr(string a) -&gt; int,那么我的目标是让编译器找出输出类型为vector&lt;int&gt;。这是我想要实现的伪代码:

template <typename Cont<InT>, typename Cont<OutT>, typename Tr<InT, OutT>>
Cont<OutT> Map(Cont<InT> cont, Tr<InT, OutT> tr)
{
    // Implementation
}

【问题讨论】:

  • 不相关,但是将函数命名为 map 有点令人困惑,因为 std::map
  • 函数式编程map == std::transform。迭代器确实允许您在 C++ 中对容器进行通用编程:使用它们。
  • 谢谢。我将其更改为Map。应该消除混乱。
  • 你应该使用迭代器
  • 顺便说一句,您也许可以使用decltype 指定输出类型

标签: c++ templates type-inference higher-order-functions


【解决方案1】:

你可以这样写:

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 也可以使用分配器

【讨论】:

  • 谢谢。这正是我所需要的。仍然存在将其用于泛型类型的问题,而不仅仅是矢量。
猜你喜欢
  • 2020-07-21
  • 2021-08-29
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2021-03-08
  • 1970-01-01
  • 2017-01-21
相关资源
最近更新 更多