【问题标题】:Passing functions as arguments to avoid repeating code将函数作为参数传递以避免重复代码
【发布时间】:2018-10-02 19:26:21
【问题描述】:

到目前为止,我一直在使用 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;
}

非常感谢您花时间审查我的问题。

【问题讨论】:

  • 示例代码是你想要实现的吗?除了你可以将convert 更改为模板template&lt;typename A, typename B&gt; double convert(const THING &amp;t, A first, B then)

标签: c++ c++11 c++14 dry overloading


【解决方案1】:

首先,您还不能使用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_Aget_B 只返回成员。我们已经有了一个语法:指向成员数据的指针(不幸的是它们不能直接调用,所以你需要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);
}

你怎么看?

【讨论】:

  • 魔术!谢谢。只是想知道,如果在不同的情况下,我有 f1()f2() 调用 convert 但它们只传递函数 get_Aget_B,并留给 convert 找到 t 到拨打电话get_A(t),我该怎么做?假设convert 可以访问t 元素的容器。现在似乎在做&amp;thing_t::A 它是通过一个隐式对象传递的。
  • @JoaquinRomera 我不明白你在问什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-13
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 2011-04-07
  • 1970-01-01
相关资源
最近更新 更多