使用 std::transform 构建 std::vector。 return 未命名结果的可能性?

constructing a std::vector using std::transform. Possibility to return unnamed result?

让我们

class InputClass; 
class OutputClass; 

OutputClass const In2Out(InputClass const &in)
{
    //conversion implemented
}

最后

std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
    std::vector<OutputClass> res;
    res.reserve(input.size());
    //either 
    for (auto const &in : input)
        res.emplace_back(In2Out(in));
    return res;
    //or something like
    std::transform(input.begin(), input.end(), std::back_inserter(res), [](InputClass const &in){return In2Out(in);});
    return res;
}  

现在我的问题

我能否以某种方式重写 Convert 函数避免命名新容器? IE。有没有一种方法可以直接使用大致类似于 std::transform 或 std::for_each 的东西来构建向量?

如(伪代码,不出所料,这不起作用甚至无法构建)

std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
    return std::transform(input.begin(), input.end(), std::back_inserter(std::vector<OutputClass>()), [](InputClass const &in){return In2Out(in);});
}

搜索过,没有找到优雅的解决方案。谢谢!

Can I rewrite the Convert function somehow avoiding the need to name the new container?

不只使用 std::transformstd::transform 本身从不创建容器。它只将元素插入到输出迭代器。为了同时将输出迭代器获取到容器,以及稍后 return 容器,您几乎需要一个名称(除非您动态分配容器,这将是愚蠢且低效的)。

您当然可以编写一个使用 std::transform 的函数,创建(命名的)向量,然后 return 存储它。然后该函数的调用者不需要关心那个名字。事实上,这几乎就是你的函数 Convert 的意思。

是的,使用 boost 时非常简单:

struct A
{
};

struct B
{
};

std::vector<B> Convert(const std::vector<A> &input)
{
    auto trans = [](const A&) { return B{}; };
    return { boost::make_transform_iterator(input.begin(), trans), boost::make_transform_iterator(input.end(), trans) };
}

https://wandbox.org/permlink/ZSqt2SbsHeY8V0mt

但是正如其他人提到的那样,这很奇怪并且没有提供任何增益(没有性能增益或可读性增益)

从 C++ 20 开始,您可以使用新的 std::ranges::transform_view 来完成您想要的。它将为其正在调整的容器中的每个元素调用您的转换函数,您可以使用该视图调用 std::vector 的迭代器范围构造函数,该构造函数将为整个向量分配一次内存,然后填充元素。它仍然需要您在函数中创建一个变量,但它变得更加精简。那会给你类似

的东西
std::vector<OutputClass> Convert(std::vector<InputClass> const &input)
{
    auto range = std::ranges::transform_view(input, In2Out);
    return {range.begin(), range.end()};
}

请注意,这应该优化为您的函数生成的完全相同的代码。