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

时间:2018-08-14 13:43:56

标签: c++ templates macros

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

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

之所以失败,是因为编译器无法找出要使用的f_()的重载。

如何替换宏h的功能?

3 个答案:

答案 0 :(得分:7)

您可以使用可变参数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_
}

答案 1 :(得分:6)

如果您不介意更改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%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<typename T>
void h(int i, double x, T t)
{
   i > 0 ? t(i, x) : t(i);
}

Exporting data stored in BigQuery无耻地复制了overloaded模板。

this example for std::visit,您必须调整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)...); }

答案 2 :(得分:0)

您不能直接执行此操作,因为为T推断的类型将需要包括参数类型,但是您可以沿着

#include <iostream>

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

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);
}

打印:

  

int