为什么STL中没有transform_if? [英] Why is there no transform_if in STL?
问题描述
当想要做一个有条件的复制(1. copy_if
)时,出现了一个用例,但从一个容器的值到一个容器指针的值。doable with transform
)。
使用可用工具,我无法在不到两个步骤中执行 :
#include< vector>
#include< algorithm>
using namespace std;
struct ha {
int i;
explicit ha(int a):i(a){}
};
int main()
{
vector< ha> v {ha {1},ha {7},ha {1}}; // initial vector
// GOAL:make a vector of pointers to elements with i< 2
vector< ha *> ph; // target vector
vector< ha *> pv; // temporary vector
// 1.
transform(v.begin(),v.end(),back_inserter(pv),
[](ha& arg){return& ; arg;})
// 2.
copy_if(pv.begin(),pv.end(),back_inserter(ph),
[](ha * parg){return parg-> i< ; 2;}); // 2.
return 0;
}
现在我们可以调用 remove_if
pv
,并且不需要临时的,但是更好的是,实现(一元操作)类似这样:
template<
class InputIterator,class OutputIterator,
class UnaryOperator,class Pred
>
OutputIterator transform_if(InputIterator first1,InputIterator last1,
OutputIterator result,UnaryOperator op,Pred pred)
{
while(first1!= last1)
{
if(pred(* first1)){
* result = op(* first1);
++ result;
}
++ first1;
}
return result;
}
//示例调用
transform_if(v.begin(),v.end(),back_inserter(ph),
[] arg){return& arg;},// 1.
[](ha& arg){return arg.i <2;}); // 2.
- 有可用的STL工具有更优雅的解决方法吗? >
- 有没有理由
transform_if
不存在的原因?
解决方案现有工具的组合是否有足够的解决方法和/ / div>标准库支持基本算法。
容器和算法应尽可能相互独立。
同样,可以由现有算法组成的算法也只是很少包括在内。
如果你需要一个变换, 。如果你想要/今天/,组成的准备好,而不是开销,你可以使用一个范围库具有<延迟范围,例如 Boost.Range ,例如:
v |过滤(arg1%2)|转换(arg1 * arg1 / 7.0)
由于@hvd在注释中指出,
transform_if
double导致不同的类型(double
,在这种情况下)。组合顺序很重要,使用Boost Range,你也可以写:v |变换(arg1 * arg1 / 7.0)|过滤(arg1 <2.0)
导致不同的语义。这带来了点:
它没有什么意义包括
。请参阅示例 Live on Colirustd :: filter_and_transform
,std :: transform_and_filter
,std :: filter_transform_and_filter
#include< boost / range / algorithm.hpp>
#include< boost / range / adaptors.hpp>
使用命名空间boost :: adapters;
//仅适用于没有lambdas的简明谓词
#include< boost / phoenix.hpp>
using namespace boost :: phoenix :: arg_names;
// for demo
#include< iostream>
int main()
{
std :: vector< int> const v {1,2,3,4,5};
boost :: copy(
v | filtered(arg1%2)| transform(arg1 * arg1 / 7.0),
std :: ostream_iterator< double>(std :: cout ,\\\
));
}
A use case emerged when wanting to do a contitional copy (1. doable with
copy_if
) but from a container of values to a container of pointers to those values (2. doable withtransform
).With the available tools I can't do it in less than two steps :
#include <vector> #include <algorithm> using namespace std; struct ha { int i; explicit ha(int a) : i(a) {} }; int main() { vector<ha> v{ ha{1}, ha{7}, ha{1} }; // initial vector // GOAL : make a vector of pointers to elements with i < 2 vector<ha*> ph; // target vector vector<ha*> pv; // temporary vector // 1. transform(v.begin(), v.end(), back_inserter(pv), [](ha &arg) { return &arg; }); // 2. copy_if(pv.begin(), pv.end(), back_inserter(ph), [](ha *parg) { return parg->i < 2; }); // 2. return 0; }
Ofcourse we could call
remove_if
onpv
and eliminate the need for a temporary, better yet though, it's not difficult to implement (for unary operations) something like this :template < class InputIterator, class OutputIterator, class UnaryOperator, class Pred > OutputIterator transform_if(InputIterator first1, InputIterator last1, OutputIterator result, UnaryOperator op, Pred pred) { while (first1 != last1) { if (pred(*first1)) { *result = op(*first1); ++result; } ++first1; } return result; } // example call transform_if(v.begin(), v.end(), back_inserter(ph), [](ha &arg) { return &arg; }, // 1. [](ha &arg) { return arg.i < 2; });// 2.
- Is there a more elegant workaround with the available STL tools ?
- Is there a reason why
transform_if
does not exist ? Is the combination of the existing tools a sufficient workaround and/or considered performance wise well behaved ?
解决方案The standard library favours elementary algorithms.
Containers and algorithms should be independent of each other if possible.
Likewise, algorithms that can be composed of existing algorithms are only rarely included, as shorthand.
If you require a transform if, you can trivially write it. If you want it /today/, composing of ready-mades and not incur overhead, you can use a range library that has lazy ranges, such as Boost.Range, e.g.:
v | filtered(arg1 % 2) | transformed(arg1 * arg1 / 7.0)
As @hvd points out in a comment,
transform_if
double result in a different type (double
, in this case). Composition order matters, and with Boost Range you could also write:v | transformed(arg1 * arg1 / 7.0) | filtered(arg1 < 2.0)
resulting in different semantics. This drives home the point:
it makes very little sense to include
std::filter_and_transform
,std::transform_and_filter
,std::filter_transform_and_filter
etc. etc. into the standard library.See a sample Live On Coliru
#include <boost/range/algorithm.hpp> #include <boost/range/adaptors.hpp> using namespace boost::adaptors; // only for succinct predicates without lambdas #include <boost/phoenix.hpp> using namespace boost::phoenix::arg_names; // for demo #include <iostream> int main() { std::vector<int> const v { 1,2,3,4,5 }; boost::copy( v | filtered(arg1 % 2) | transformed(arg1 * arg1 / 7.0), std::ostream_iterator<double>(std::cout, "\n")); }
这篇关于为什么STL中没有transform_if?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文