我正在尝试按位或'|'重载操作符,以便我可以将不同的操作一个接一个地链接。
我实现了以下代码。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Test
{
explicit Test(vector<int> vdata) : data_(vdata) { }
vector<int>& operator()()
{
return data_;
}
template<typename Pred>
Test operator | (Pred P)
{
*this = P;
return *this;
}
vector<int> data_;
};
template <typename Con, typename Pred>
Con Transform(Con& C, Pred P)
{
vector<int> res;
transform(begin(C()), end(C()),back_inserter(res), P);
return Con(res);
}
template <typename Con, typename Pred>
Con Filter(Con& C, Pred P)
{
vector<int> res;
remove_copy_if(begin(C()), end(C()), back_inserter(res), P);
return Con(res);
}
int main()
{
vector<int> vdata{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
auto DoubleIt = [](int& v) {
return v *= 2;
};
auto Remove_Lteq4 = [](auto v) {
return v <= 4;
};
auto Remove_divideby3=[](auto v)
{
return !(v % 3);
};
Test test(vdata);
Test test1 =
test | Filter(test, Remove_Lteq4) |
Transform(test, DoubleIt) |
Filter(test, Remove_divideby3);
// output
for (auto v : test1())
cout << v << " ";
}
代码运行良好,可以在Cxxdroid 2.0_arm离线编译器C ++ 14 / C ++ 17上提供预期的输出,但是我在在线编译器上得到了不同的结果
输入: 向量= {1,2,3,4,5,6,7,8,9,10,11,12} 依次应用的操作是 过滤器值<= 4,然后将剩余值乘以2,然后将过滤器值除以3
结果离线编译器(Cxxdroid) 预期输出:10、14、16、20、22 实际输出:10、14、16、20、22
在线编译器 实际输出:1,2,4,5,7,8,10,11(如果仅对输入应用remove_divideby3函数,则实际上是输出)。
我正在努力解决它一段时间,无法弄清输出不同的原因。有人可以告诉我我在哪里犯错。 如果我一次只应用一种操作,则代码可以正常工作。
如果有人可以回答其他查询,我也将非常感激。
我是否需要编写副本构造函数/副本分配,移动构造函数和移动分配。
在按值和按引用传递和返回对象方面,我对对象的用法是否正确?我认为问题出在这里,可能在需要引用的地方传递对象。
是否需要重载'|'在全球范围内。
注意:使用命名空间std;仅出于方便的目的,因为我在手机上键入了代码。
谢谢
答案 0 :(得分:1)
您正在执行此操作(我重新排列了管道以使其更易于阅读):
Test test1 =
test | Filter(test, Remove_Lteq4)
| Transform(test, DoubleIt)
| Filter(test, Remove_divideby3);
让我们从后面开始。 Filter(test, Remove_divideby3)
是做什么的?它返回一个容器,该容器包含test
中满足Remove_divideby3
的所有元素。但是test
是您的开始,它不依赖于此操作的任何部分。另一个Filter
或Transform
返回什么都无关紧要,因为这些值都不用作此Filter
的输入。
这就是为什么您得到的与写的没有什么不同的原因:
Test test1 = Filter(test, Remove_divideby3);
您的适配器 都将范围作为参数:
Filter(Transform(Filter(test, Remove_Lteq4), DoubleIt), Remove_divideby3)
或使用管道:
test | Filter(Remove_Lteq4) | Transform(DoubleIt) | Filter(Remove_divideby3)
不能同时使用。
答案 1 :(得分:1)
template<class F>
struct pipe_func {
F f;
template<class Lhs>
friend auto operator|( Lhs&& lhs, pipe_func rhs ) {
return rhs.f( std::forward<Lhs>(lhs) );
}
};
template<class F>
pipe_func(F)->pipe_func<F>;
有一个构建基块。 pipe_target
接受一个函数,当通过管道传输的东西将其馈送到该函数并返回结果时。
现在假设您要编写过滤器。
template<class Pred>
auto Filter( Pred p ) {
return pipe_func{[p]( auto&& container ) {
using std::begin; using std::end;
using R = std::decay_t< decltype(container) >;
R retval;
std::remove_copy_if( begin(container), end(container), std::back_inserter(retval), p );
return retval;
}};
}
所以filter
是一个带有谓词的函数。
它返回一个pipe_func
。 pipe_func
中有一个lambda来应用谓词。
转换类似:
template<class Pred>
auto Transform( Pred p ) {
return pipe_func{[p]( auto&& container ) {
using std::begin; using std::end;
using R = std::decay_t< decltype(container) >;
R retval;
std::transform( begin(container), end(container), std::back_inserter(retval), p );
return retval;
}};
}
测试代码如下:
std::vector<int> test1 =
vdata | Filter(Remove_Lteq4) |
Transform(DoubleIt) |
Filter(Remove_divideby3);
现在,我们可以将带有两个参数的函数传递给函数的解决方案有点麻烦;该函数仍然认为它需要2个参数,因此将第二个参数传递给它很棘手。
我会避免的。任何解决方案都是骇客。