【问题标题】:runtime specialization of overloaded function重载函数的运行时特化
【发布时间】:2016-09-20 10:15:21
【问题描述】:

这是 this SO question 的变体。我有一个重载函数,它接受不同类型的参数并返回不同类型:

struct mystruct {
  auto f (int x, int y) -> int;
  auto f (std::string x, int y) -> float;
};

函数f 需要使用其参数之一多次调用自身。 我想定义一个专门用于参数y 的函数,即我想要g(z) = f(z,y)g 的返回类型及其唯一参数z 变量的类型,但两种情况下的实现是相同的。

对于这种情况,我能找到的最佳实现是重载 lambda 函数:

template <class F1, class F2>
struct overload_set : F1, F2
{
  overload_set(F1 f1, F2 f2) : F1(f1), F2(f2) {}

  using F1::operator();
  using F2::operator();
};
template <class F1, class F2>
overload_set<F1, F2> overload(F1 f1, F2 f2) {
  return overload_set<F1, F2>(f1, f2);
};

struct mystruct { 
  auto f( std::string x, int y) -> float {
  return y+9.3;
  }
  auto f( int x, int y) -> int
  {
    auto g = overload (
      [=]( int z ) -> int {return f(z,y);},
      [=]( std::string z) -> float { return f(z,y); }
    );
  if ( x == 0 ) {
    std::cout << g("this string") << "\n";
    return 0;
  }
  if ( x == 1 ) return y;
  return 7;
  }
};
int main () {
  mystruct h;
  std::cout << h.f(1,4) << "\n";
  std::cout << h.f(0,2) << "\n";
}

按预期工作,但似乎有点矫枉过正。似乎是一个简单的预处理宏

#define k(z) f(z,y)

也可以。有什么好的方法可以实现吗?

【问题讨论】:

  • 你受限于 c++11 吗?为什么不直接使用auto g(auto z) -&gt; decltype(f(z, y))
  • 我试过了,但没有用,如果您发布适用于该方法的代码作为答案,我会接受并感谢您。
  • 新案例中y从何而来?

标签: c++ templates lambda


【解决方案1】:

不确定这是否是您尝试做的,但这是一个有效的 (c++14) 示例:

#include <iostream>

struct mystruct {
  static auto f (int x, int y) -> int {
     std::cout << "f(" << x << "," << y << ")" << std::endl;
     auto g = [=](auto z) -> decltype(mystruct::f(z, y)) {
       return mystruct::f(z, y);
     };
     if (x < 1)
        g("end");
     else
        g(x - 1);
  }
  static auto f (std::string x, int y) -> float {
     std::cout << "f(\"" << x << "\"," << y << ")" << std::endl;
  }
};

int main() {
   mystruct::f(10, 1);
}

输出:

f(10,1)
f(9,1)
f(8,1)
f(7,1)
f(6,1)
f(5,1)
f(4,1)
f(3,1)
f(2,1)
f(1,1)
f(0,1)
f("end",1)

【讨论】:

  • 哦,抱歉,我在我原来的问题中发帖,但不是在这个问题中,g 将在f 中调用,如我的示例所示。我将编辑问题
  • 所以这是一种递归(?)我不认为这会改变逻辑中的任何东西......虽然我不确定你什么时候想调用其中一个重载以及另一个...它是否依赖于运行时参数值?
  • 是的,函数g 应该是一个包装器,它只调用 f ,一堆参数相同,只改变一个参数。在我的问题示例中,这是可行的,但它有点复杂。我不知道如何使您的示例以这种方式工作
  • 我已经编辑了答案。我认为您需要做的第一件事是定义边界条件,即当您想要递归停止时......
  • 这仅适用于静态 f,但它比我的重载 lambda 更简单,我可以实现它。谢谢
【解决方案2】:

我错过了什么吗?

这产生了相同的答案,我认为更清楚一点:

#include <string>
#include <iostream>

struct mystruct
{
    auto f( std::string x, int y) -> float {
        return y+9.3;
    }

    auto f( int x, int y) -> int
    {
        switch(x)
        {
            case 0: {
                auto g = [=](auto...args) { return f(args..., y); };
                std::cout << g("this string") << "\n";
                return 0;
            } break;

            case 1: {
                return y;
            } break;

            default:
                return 7;
        }
    }
};
int main () {
    mystruct h;
    std::cout << h.f(1,4) << "\n";
    std::cout << h.f(0,2) << "\n";
}

也许实际上有更多的switch case,g需要被提升到switch语句之上?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多