如何将多个函数重载作为单个参数传递?

How can I pass multiple function overloads as a single argument?

本文关键字:单个 参数传递 重载 函数      更新时间:2023-10-16

这是试图摆脱宏的另一种情况。考虑

void f_(int i) { printf("f_(int)t%dn", i); }
void f_(int i, double x) { printf("f_(int, double)t%d, %5.3fn", i, x); }
void g_(int i) { printf("g_(int)t%dn", i); }
void g_(int i, double x) { printf("g_(int, double)t%d, %5.3fn", i, x); }

(想象一下,f_().foo文件中获取数据或使用硬编码的"虚拟"值,g_().bar执行相同的操作。 可能有一个函数来决定调用哪个重载:

void f(int i, double d) { (i > 0) ? f_(i, d) : f_(i); }

g_()相同的逻辑重复:

void g(int i, double x) { (i > 0) ? g_(i, x) : g_(i); }

使用宏可以轻松删除重复的代码:

#define h(i, x, func_) (i > 0) ? func_(i, x) : func_(i);
// ...
h(-1, 314.1, f_);
h(99, 314.1, f_);
h(-1, 314.1, g_);
h(99, 314.1, g_);

但是,当然,我们宁愿不要在C++中使用宏。 "显而易见"的模板

template<typename T>
void h2(int i, double x, T t)
{
(i > 0) ? t(i, x) : t(i);
}
// ...
h2(-1, 314.1, f_);

失败,因为编译器无法确定要使用的f_()重载。

如何替换宏h的功能?

您可以使用可变参数 lambda 并让 lambda 调用您要调用的函数。

template<typename T>
void h2(int i, double x, T t)
{
i > 0 ? t(i, x) : t(i);
}
int main()
{
h2(-1, 314.1, [](auto... args){ f_(args...); });
//                              ^^ change this to g_ if you want to use g_ instead of f_
}

如果你不介意改变f_g_的定义,你可以做类似的事情

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
auto f_ = overloaded(
[](int i) { printf("f_(int)t%dn", i); },
[](int i, double x) { printf("f_(int, double)t%d, %5.3fn", i, x); }
);
auto g_ = overloaded(
[](int i) { printf("g_(int)t%dn", i); },
[](int i, double x) { printf("g_(int, double)t%d, %5.3fn", i, x); }
);

那么你的h模板正是你想要的

template<typename T>
void h(int i, double x, T t)
{
i > 0 ? t(i, x) : t(i);
}

overloaded模板无耻地从此示例中复制std::visit.

要使其适用于 C++11,您必须调整overloaded模板并添加一个帮助程序函数来推断类型参数

template<class... Ts> struct overloads;
template<> struct overloads<>{};
template<class T, class... Ts> struct overloads<T, Ts...> : T, overloads<Ts...> 
{ 
overloads(T t, Ts... ts) : T(t), overloads<Ts...>(ts...) {}
using T::operator(); 
};
template<class... Ts> overloads<Ts...> overloaded(Ts&&... ts) 
{ return overloads<Ts...>(std::forward<Ts>(ts)...); }

您不能直接执行此操作,因为推断T的类型需要包含参数类型,但您可以按照以下命令行执行一些操作

#include <iostream>

struct overloader {
void foo(int) { std::cout << "intn";}
void foo(double) { std::cout << "doublen";}
};

template <typename T>
void bar(int x,double y,bool opt, T t){
if (opt) { t.foo(x); }
else { t.foo(y); }
}

int main() {
overloader ol;
bar(1,1,true,ol);
bar(1,1,false,ol);
}

指纹:

国际