作者:cuishy | 来源:互联网 | 2022-12-07 18:03
这是试图摆脱宏的另一种情况.考虑
void f_(int i) { printf("f_(int)\t%d\n", i); }
void f_(int i, double x) { printf("f_(int, double)\t%d, %5.3f\n", i, x); }
void g_(int i) { printf("g_(int)\t%d\n", i); }
void g_(int i, double x) { printf("g_(int, double)\t%d, %5.3f\n", 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
void h2(int i, double x, T t)
{
(i > 0) ? t(i, x) : t(i);
}
// ...
h2(-1, 314.1, f_);
失败,因为编译器无法弄清楚f_()
要使用的重载.
如何替换宏的功能h
?
1> NathanOliver..:
您可以使用可变参数lambda并让lambda调用您想要调用的函数.
template
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_
}
2> Caleth..:
如果你不介意改变定义的中f_
和g_
,你可以这样做
template struct overloaded : Ts... { using Ts::operator()...; };
template overloaded(Ts...) -> overloaded;
auto f_ = overloaded(
[](int i) { printf("f_(int)\t%d\n", i); },
[](int i, double x) { printf("f_(int, double)\t%d, %5.3f\n", i, x); }
);
auto g_ = overloaded(
[](int i) { printf("g_(int)\t%d\n", i); },
[](int i, double x) { printf("g_(int, double)\t%d, %5.3f\n", i, x); }
);
然后你的h
模板正是你想要的
template
void h(int i, double x, T t)
{
i > 0 ? t(i, x) : t(i);
}
该overloaded
模板无耻地从复制这个例子std::visit
.
要使其适用于C++ 11,您必须调整overloaded
模板并添加辅助函数以推断类型参数
template struct overloads;
template<> struct overloads<>{};
template struct overloads : T, overloads
{
overloads(T t, Ts... ts) : T(t), overloads(ts...) {}
using T::operator();
};
template overloads overloaded(Ts&&... ts)
{ return overloads(std::forward(ts)...); }
@Ð是一个技巧是制作单个对象而不是单个名称.我只记得`std :: variant`示例作为一种有用的模式
@rustyx我认为你可以做一个C++ 11变体,它只涉及一个`make_`函数而不是一个演绎指南