为什么STL中没有transform_if? [英] Why is there no transform_if in STL?

查看:142
本文介绍了为什么STL中没有transform_if?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当想要做一个有条件的复制(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.




  1. 有可用的STL工具有更优雅的解决方法吗? >
  2. 有没有理由 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)

导致不同的语义。这带来了点:


它没有什么意义包括 std :: filter_and_transform std :: transform_and_filter std :: filter_transform_and_filter

请参阅示例 Live on Coliru

  #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 with transform).

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 on pv 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.

  1. Is there a more elegant workaround with the available STL tools ?
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆