代码之家  ›  专栏  ›  技术社区  ›  Ðаn

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

  •  8
  • Ðаn  · 技术社区  · 6 年前

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

    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_() 获取数据表A 文件或使用硬编码的“虚拟”值, g_() 对……也一样 酒吧 .)可能有一个函数来决定调用哪个重载:

    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 回复  |  直到 6 年前
        1
  •  6
  •   Caleth    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);
    }
    

    这个 overloaded 模板无耻地复制自 this example for std::visit .

    To make it work for C++11 你必须适应 超载 模板并添加一个助手函数来推导类型参数

    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
  •  7
  •   NathanOliver    6 年前

    您可以使用变量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_
    }
    
        3
  •  0
  •   463035818_is_not_an_ai    6 年前

    不能直接执行,因为推断的类型 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

    双重的