重载函数的运行时特化

时间:2016-09-20 10:15:21

标签: c++ templates lambda

这是 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)

也会奏效。有没有一种很好的方法来实现这一目标?

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分:0)

我错过了什么吗?

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

#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";
}

也许实际上有更多的切换案例,并且需要在g声明之上悬挂switch