如何转换嵌套的C ++ 11绑定表达式

时间:2013-12-02 21:42:45

标签: c++ c++11 metaprogramming bind compile-time

是否可以转换嵌套的C ++ 11绑定表达式?例如,在下面的代码中,与f关联的绑定表达式将首先将其参数乘以2,然后在结果中添加一个:

#include <iostream>
#include <functional>

using namespace std::placeholders;

int main(int argc, char *argv[])
{                                                                               
  auto add1 = [](int x) { return x+1; };
  auto mul2 = [](int x) { return x*2; };

  auto f = std::bind(add1, std::bind(mul2, _1));
  std::cout << f(0) << '\n';
  return 0;
}

我们是否可以创建f的转换版本,而首先添加一个,然后将结果乘以2;结果的行为就像定义为:

auto f2 = std::bind(mul2, std::bind(add1, _1));

这个例子简化为它的结构类似于列表;而绑定表达式通常更像是树。

2 个答案:

答案 0 :(得分:5)

std::bind是一个黑盒子。它不支持内省(除了std::result_ofstd::is_bind_expression)或多态(除std::placeholders之外)。当您致电f(0)时,它会编译为0*2+1的原生代码。

在黑盒子里面就像一个表达式模板,引用组合的仿函数类型并为任何绑定参数提供存储。这种实现与编译器有关,平台细节实际上差别很大。

如果要移植操作表达式,请查看Boost.Proto通用表达式模板库。不过,这很重要。

答案 1 :(得分:3)

这是对VS2013的残酷破解,并且完全不可移植,但我有兴趣看看我能不能做些什么。它可能无法解决您的问题,但我认为值得分享。由于std::bind的返回值是实现定义的,因此可移植性将成为此问题的一大障碍。大部分模板演绎也有很多手段。

template<class A, class B, class C>
std::_Bind<false, void, B&, std::_Bind<false, void, A&, C>> 
inverse(std::_Bind<false, void, A&, std::_Bind<false, void, B&, C>> f) {
    A func_a;
    B func_b;
    return std::bind(func_b, std::bind(func_a, _1));
}

int main() {
    auto add1 = [](int x) { return x+1; };
    auto mul2 = [](int x) { return x*2; };

    auto f = std::bind(add1, std::bind(mul2, _1));
    std::cout << f(0) << '\n';

    auto g = inverse(f);
    std::cout << g(0) << '\n';

    return 0;
}