首页 > 解决方案 > 为链接操作重载按位 OR('|') 无法按预期工作

问题描述

我正在尝试按位重载 OR '|' 运算符,这样我就可以一个接一个地链接不同的操作。

我已经实现了以下代码。

#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 上给出了预期的输出,但我在在线编译器上得到了不同的结果

输入:vector = {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 函数应用于输入时会得到的输出)。

我已经为此苦苦挣扎了一段时间,无法找出不同输出的原因。有人可以告诉我在哪里犯了错误。如果我一次只应用一个操作,代码就可以正常工作。

如果有人可以回答附加查询,我也将非常感激。

  1. 我是否需要编写复制构造函数/复制赋值、移动构造函数和移动赋值。

  2. 在按值和按引用传递和返回对象方面,我对对象的使用是否正确。我认为问题出在此处,可能是在需要引用的地方传递了一个对象。

  3. 是否需要重载'|' 在全球层面。

注意:使用命名空间标准;仅用于方便目的,因为我在移动设备上输入了代码。

谢谢

标签: c++operator-overloadingc++17

解决方案


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>;

有一个适合你的积木。Apipe_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 个参数,因此传递它的第二个参数是很棘手的。

我会避免它。任何解决方案都将是一个黑客。


推荐阅读