有没有一种惯用的方法在 C++ 中创建 U 到 V 映射器函数模板?

问题描述 投票:0回答:1

我现在正在学习 C++,并尝试一些模板功能。我正在尝试创建一个通用模板,该模板接收从

F
U
的函数
V
std::array
类型的
U
),然后返回(通过 NRVO)类型为
V
的数组。

这是我第一次想到的。对于我未经训练的眼睛来说,这似乎是合理的,但编译器不喜欢它:

template <typename F, typename U, typename V, std::size_t N> std::array<V, N> map(F mapper, std::array<U, N> &elements)
{
  std::array<V, N> newArray{};
  for (std::size_t i = 0; i < N; i++) {
    newArray[i] = mapper(elements[i]);
  }
  return newArray;
}

// ...

int main()
{
  std::array<int, 10> ints1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  auto doubles1 = map([](int x) -> double { return x*2.5; }, ints1);
}

我正在使用 clang 16.0.6,它告诉我:

functional.cpp:87:19: error: no matching function for call to 'map'
  auto doubles1 = map([](int x) -> double { return x*2.5; }, ints1);
                  ^~~~~~~~~~~~
functional.cpp:22:79: note: candidate template ignored: couldn't infer template argument 'V'
template <typename F, typename U, typename V, std::size_t N> std::array<V, N> map(F mapper, std::array<U, N> &elements)
                                                                              ^
1 error generated.

在我看来,我似乎应该做一些事情来提示编译器 lambda 返回一个 double,因此

auto
应该被推导为
std::array<double, N>
。我缺少什么简单的东西吗?谢谢你。

我当然希望代码能够编译,但有些事情不太正确。我对 C++ 术语还很陌生,所以我不知道到底要谷歌什么来解决这个问题。我想出的一种可能的解决方案是使用外参数:

template <typename F, typename U, typename V, std::size_t N> void map_outParam(F mapper, std::array<U, N> &elements, std::array<V, N> &out)
{
  for (std::size_t i = 0; i < N; i++) {
    out[i] = mapper(elements[i]);
  }
}

编译得很好,并且按预期工作。然而,它并不像我想要的那么干净。

c++ templates functional-programming c++17 c++20
1个回答
0
投票

你很接近,但模板参数的顺序令人困惑:

#include <cstddef>
#include <array>
#include <iostream>

template <typename V, std::size_t N, typename F, typename U>
std::array<V, N> map(
    F mapper,
    std::array<U, N>& elements
) {
  std::array<V, N> newArray{};
  for (std::size_t i = 0; i < N; i++) {
    newArray[i] = mapper(elements[i]);
  }
  return newArray;
}

// ...

int main()
{
    std::array<int, 10> ints1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto doubles1 = map<double>(
        [](int x) -> double {
            return x*2.5; 
        },
        ints1
    );

    for (auto it = doubles1.begin(); it != doubles1.end(); ++it) {
        std::cout<<*it<<'\n';
    }
}

区别在于存在隐式模板参数的概念,编译器在其中推导模板类型。您最初订购它们的方式不尊重无法推断出

V
,因此没有匹配的功能。

因此上面的示例调整了顺序并明确定义了

V
是什么。

© www.soinside.com 2019 - 2024. All rights reserved.