将函数作为参数传递以避免重复代码

jrs*_*jrs 2 c++ overloading dry c++11 c++14

到目前为止,我一直在使用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;
}
Run Code Online (Sandbox Code Playgroud)

非常感谢您抽出宝贵的时间来回顾我的问题.

Bar*_*rry 6

首先,您还不能获取auto功能参数.这是非标准的C++.这typedef struct件事也是C-ism.在C++中,只需:

struct thing_t {
    double A;
    double B;
};
Run Code Online (Sandbox Code Playgroud)

现在让我们来谈谈概括.是否convert需要了解它的参数?也许它本身就是一个更高阶的函数:

template <typename F, typename G>
auto convert(F f, G g) {
    return [=](auto const& x) { return f(x) / g(x); }
}
Run Code Online (Sandbox Code Playgroud)

然后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);
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

你对那个怎么想的?