将函数作为参数传递以避免重复代码
Passing functions as arguments to avoid repeating code
到目前为止,我一直在使用 C++11 进行编码,并且我正在尝试了解 auto 在较新版本中的工作原理。特别是我有两个函数(示例中的 f1 和 f2)在给定结构上工作。这两个函数几乎相同,但它们根据操作的成员而改变,有时操作是一个值的倒数,等等......(这个例子是对真实程序的过度简化)。
我想避免使用条件语句和重载函数来实现此行为。您知道更清洁或更惯用的方法吗?我遗漏了这段代码中的任何问题吗?
typedef struct thing_t {
double A;
double B;
} THING;
double get_A(const THING &t) {
return t.A;
}
double get_B(const THING &t) {
return t.B;
}
double convert(const THING &t, auto first, auto then) {
return first(t) / then(t);
}
double f1(const THING &t) {
return convert(t, get_A, get_B);
}
double f2(const THING &t) {
return convert(t, get_B, get_A);
}
int main() {
THING t = {1.0, 2.0};
std::cout << f1(t) << std::endl;
std::cout << f2(t) << std::endl;
return 0;
}
非常感谢您抽出时间审阅我的问题。
首先,您还不能使用 auto
函数参数。那是非标准的 C++。这 typedef struct
也是 C 主义。在 C++ 中,只是:
struct thing_t {
double A;
double B;
};
现在让我们谈谈概括。 convert
需要知道它的参数吗?也许它本身就是一个高阶函数:
template <typename F, typename G>
auto convert(F f, G g) {
return [=](auto const& x) { return f(x) / g(x); }
}
然后 get_A
和 get_B
只是 return 成员。我们已经有了一个语法:指向成员数据的指针(不幸的是,它们不能直接调用,所以你需要 std::mem_fn
):
double f1(const thing_t& t) {
return convert(std::mem_fn(&thing_t::A), std::mem_fn(&thing_t::B))(t);
}
C++17 引入了 std::invoke
,因此您可以使此处的实用程序函数更加人性化。它可以在 C++14 中很好地实现,但它会让你写:
template <typename F, typename G>
auto convert(F f, G g) {
return [=](auto const& x) { return std::invoke(f, x) / std::invoke(g, x); };
}
double f1(const thing_t& t) {
return convert(&thing_t::A, &thing_t::B)(t);
}
double f2(const thing_t& t) {
return convert(&thing_t::B, &thing_t::A)(t);
}
你怎么看?
到目前为止,我一直在使用 C++11 进行编码,并且我正在尝试了解 auto 在较新版本中的工作原理。特别是我有两个函数(示例中的 f1 和 f2)在给定结构上工作。这两个函数几乎相同,但它们根据操作的成员而改变,有时操作是一个值的倒数,等等......(这个例子是对真实程序的过度简化)。
我想避免使用条件语句和重载函数来实现此行为。您知道更清洁或更惯用的方法吗?我遗漏了这段代码中的任何问题吗?
typedef struct thing_t {
double A;
double B;
} THING;
double get_A(const THING &t) {
return t.A;
}
double get_B(const THING &t) {
return t.B;
}
double convert(const THING &t, auto first, auto then) {
return first(t) / then(t);
}
double f1(const THING &t) {
return convert(t, get_A, get_B);
}
double f2(const THING &t) {
return convert(t, get_B, get_A);
}
int main() {
THING t = {1.0, 2.0};
std::cout << f1(t) << std::endl;
std::cout << f2(t) << std::endl;
return 0;
}
非常感谢您抽出时间审阅我的问题。
首先,您还不能使用 auto
函数参数。那是非标准的 C++。这 typedef struct
也是 C 主义。在 C++ 中,只是:
struct thing_t {
double A;
double B;
};
现在让我们谈谈概括。 convert
需要知道它的参数吗?也许它本身就是一个高阶函数:
template <typename F, typename G>
auto convert(F f, G g) {
return [=](auto const& x) { return f(x) / g(x); }
}
然后 get_A
和 get_B
只是 return 成员。我们已经有了一个语法:指向成员数据的指针(不幸的是,它们不能直接调用,所以你需要 std::mem_fn
):
double f1(const thing_t& t) {
return convert(std::mem_fn(&thing_t::A), std::mem_fn(&thing_t::B))(t);
}
C++17 引入了 std::invoke
,因此您可以使此处的实用程序函数更加人性化。它可以在 C++14 中很好地实现,但它会让你写:
template <typename F, typename G>
auto convert(F f, G g) {
return [=](auto const& x) { return std::invoke(f, x) / std::invoke(g, x); };
}
double f1(const thing_t& t) {
return convert(&thing_t::A, &thing_t::B)(t);
}
double f2(const thing_t& t) {
return convert(&thing_t::B, &thing_t::A)(t);
}
你怎么看?