如何创建一个函子作为2个函子的总和
How to create a functor as the sum of 2 functors?
假设我有2个函数添加和mult。add2(x) = x+2
和mult3(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
另一个选项是在应用程序特定的名称空间中创建类型add
,mult
,plus
和minus
,然后添加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";
}
相关文章:
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 如何返回一个类的两个对象相加的结果
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- 我需要将多个函数组合为一个函数
- 获取向量C++中第一个值和最后一个值的和
- 在多个核心中处理一个HTTP请求
- 从多个源构造一个对象,包括一个对象向量
- 如何通过按下第三个窗口中的按钮,将QString从一个窗口获取到另一个窗口
- C++需要帮助从用户那里获得一个整数,并确保它在另外两个整数之间
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 为什么C++在将一个对象复制到另一个对象时需要对这两个对象进行低级常量限定
- int数据类型的指针指向的是什么,如果是一个类的私有数据成员,我们创建了该类的两个对象?
- 我可以创建一个包含两个变量的 for 循环,但时间复杂度仍然为 O(n) 吗?
- 在C++行尾写一个分号或多个分号是否会改变任何内容
- 为我的 c++ 类介绍制作一个三角形分类器.我有几个问题
- 为什么有时我输入一个整数,程序将第一个输入的数字打印成十进制数?
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 一个Q_PROPERTY可以泛化为多个基类吗?
- Lower_bound不适用于具有 3 个元素的向量的最后一个元素