如何创建一个函子作为2个函子的总和

How to create a functor as the sum of 2 functors?

本文关键字:2个 一个 何创建 创建      更新时间:2023-10-16

假设我有2个函数添加和mult。add2(x) = x+2mult3(x) = 3x。我想创建一个组合的张量t,以便t(x) = x+2 + 3x。我提出了创建 Pair 函数的解决方案,但是我不太满意,因为该解决方案没有扩展到更高数量的函子。我有什么选择?

struct add {
private:
    double c_;
public:
    add(double& c): c_(c) {}
    double operator()(double& x) {
        return c_ + x;
    }
};
struct mult {
private:
    double c_;
public:
    mult(double& c): c_(c) {}
    double operator()(double& x) {
        return c_ * x;
    }
}
template<typename T1, typename T2>
struct pair {
private:
    T1 t1_;
    T2 t2_;
public:
    pair(T1 t1, T2 t2): t1_(t1), t2_(t2) {}
    double operator()(double& x) {
        return t1_(x) + t2_(x);
    }
}
add add2 = add(2);
mult mult3 = mult(3);
pair combined = pair(add2, mult3);

名称pair对函数的作用并不重要。我认为沿着以下几行创建一些东西是有意义的:

template<typename T1, typename T2>
struct plus
{
   plus(T1 t1, T2 t2) : t1_(t1), t2_(t2) {}
   double operator()(double x)
   {
      return t1_(x) + t2_(x);
   }
   T1 t1_;
   T2 t2_;
};

并提供一个辅助功能以制作这种类型的实例。

template<typename T1, typename T2>
plus<T1, T2> make_plus(T1 t1, T2 t2)
{
   return plus<T1, T2>(t1, t2);
}

然后,您可以使用:

add add2 = add(2);
mult mult3 = mult(3);
auto comb1 = make_plus(add2, mult3);
auto comb2 = make_plus(mult(10), make_plus(add2, mult3));

这是一个添加minus的程序。

#include <iostream>
struct add
{
   add(double c): c_(c) {}
   double operator()(double x) {
      return c_ + x;
   }
   double c_;
};
struct mult
{
   mult(double c): c_(c) {}
   double operator()(double x) {
      return c_ * x;
   }
   double c_;
};
template<typename T1, typename T2>
struct plus
{
   plus(T1 t1, T2 t2) : t1_(t1), t2_(t2) {}
   double operator()(double x)
   {
      return t1_(x) + t2_(x);
   }
   T1 t1_;
   T2 t2_;
};
template<typename T1, typename T2>
plus<T1, T2> make_plus(T1 t1, T2 t2)
{
   return plus<T1, T2>(t1, t2);
}
template<typename T1, typename T2>
struct minus
{
   minus(T1 t1, T2 t2) : t1_(t1), t2_(t2) {}
   double operator()(double x)
   {
      return t1_(x) - t2_(x);
   }
   T1 t1_;
   T2 t2_;
};
template<typename T1, typename T2>
minus<T1, T2> make_minus(T1 t1, T2 t2)
{
   return minus<T1, T2>(t1, t2);
}

int main()
{
   add add2 = add(2);
   mult mult3 = mult(3);
   auto comb1 = make_plus(add2, mult3);
   auto comb2 = make_plus(mult(10), make_plus(add2, mult3));
   auto comb3 = make_minus(mult(10), make_plus(add2, mult3));
   std::cout << comb1(10) << std::endl;
   std::cout << comb2(10) << std::endl;
   std::cout << comb3(10) << std::endl;
}

输出:

42
142
58

另一个选项是在应用程序特定的名称空间中创建类型addmultplusminus,然后添加operator+operator- Overloads以使main中的代码更加直观。

>
#include <iostream>
namespace myapp
{
   struct identity
   {
      double operator()(double x) { return x;}
   };
   struct add
   {
      add(double c): c_(c) {}
      double operator()(double x) {
         return c_ + x;
      }
      double c_;
   };
   struct mult
   {
      mult(double c): c_(c) {}
      double operator()(double x) {
         return c_ * x;
      }
      double c_;
   };
   template<typename T1, typename T2>
      struct plus
      {
         plus(T1 t1, T2 t2) : t1_(t1), t2_(t2) {}
         double operator()(double x)
         {
            return t1_(x) + t2_(x);
         }
         T1 t1_;
         T2 t2_;
      };
   template<typename T1, typename T2>
      plus<T1, T2> make_plus(T1 t1, T2 t2)
      {
         return plus<T1, T2>(t1, t2);
      }
   template<typename T1, typename T2>
      plus<T1, T2> operator+(T1 t1, T2 t2)
      {
         return make_plus(t1, t2);
      }
   template<typename T1, typename T2>
      struct minus
      {
         minus(T1 t1, T2 t2) : t1_(t1), t2_(t2) {}
         double operator()(double x)
         {
            return t1_(x) - t2_(x);
         }
         T1 t1_;
         T2 t2_;
      };
   template<typename T1, typename T2>
      minus<T1, T2> make_minus(T1 t1, T2 t2)
      {
         return minus<T1, T2>(t1, t2);
      }
   template<typename T1, typename T2>
      minus<T1, T2> operator-(T1 t1, T2 t2)
      {
         return make_minus(t1, t2);
      }
}
int main()
{
   using namespace myapp;
   add add2 = add(2);
   mult mult3 = mult(3);
   auto comb1 = add2 + mult3;
   auto comb2 = mult(10) +  add2 + mult3;
   auto comb3 = mult(10) - (add2 + mult3);
   auto comb4 = identity{} + add(25);
   std::cout << comb1(10) << std::endl;
   std::cout << comb2(10) << std::endl;
   std::cout << comb3(10) << std::endl;
   std::cout << comb4(10) << std::endl;
}

这是使用多态性lambdas(需要C 14)的相当简洁的解决方案。简而言之,此示例使用命名函数,仅支持一个函数参数。但是,扩展这种方法以支持多个参数和使用操作员过载更为自然的呼叫语法非常容易。

wandbox上的演示

#include <type_traits>
struct arg_t {};
auto eval(auto const& x, arg_t) {
  return x;
}
template <typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
auto eval(auto const&, T const& t) {
  return t;
}
template <typename F, std::enable_if_t<!std::is_arithmetic<F>::value, int> = 0>
auto eval(auto const& x, F const& f) {
  return f(x);
}
auto binary(auto const& a, auto const& b, auto const& f) {
  return [a, b, f](auto const& v) { return f(eval(v, a), eval(v, b)); };
}
auto sum(auto const& a, auto const& b) {
  return binary(a, b, [](auto const& a, auto const& b) { return a + b; });
}
auto product(auto const& a, auto const& b) {
  return binary(a, b, [](auto const& a, auto const& b) { return a * b; });
}

然后像这样打电话:

#include <iostream>
int main() {
  arg_t x;
  auto f = sum(sum(x, 2), product(3, x));
  std::cout << f(4) << "n";
}
相关文章: