使用 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::transform
。 std::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()};
}
请注意,这应该优化为您的函数生成的完全相同的代码。
让我们
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::transform
。 std::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()};
}
请注意,这应该优化为您的函数生成的完全相同的代码。