【问题标题】:How to transform a nested C++11 bind expression如何转换嵌套的 C++11 绑定表达式
【发布时间】:2013-12-18 18:15:49
【问题描述】:

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

#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 的转换版本,而不是首先 加一,然后 将结果乘以二;结果的行为就像定义为:

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

这个例子被简化了,因为它的结构类似于一个列表;而绑定表达式通常是一棵树。

【问题讨论】:

  • 那有什么用?您通常无法反转组合(在这里完全忽略绑定),并且您也不了解bind 的内部结构。
  • @Xeo 可能是一种函数式方法,但如果 OP 喜欢函数式,我认为 C++ 下对它的支持并不多,或者至少 C++ 它不是一种真正的函数式语言。
  • @Xeo 我一般不想反转构图。这只是一个简单的例子。我想探索转换绑定表达式的可能性。我可能会选择一个子树;或来自聚合结构的单个函数对象。现在,我会对相反的情况感到满意。谢谢。
  • std::bind 的返回值未指定。你必须定义自己的编译时树才能做你想做的事。
  • 如果你想做这样的事情,请查看 Boost.Proto。它构建了可以遍历和操作的表达式树。

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


【解决方案1】:

这是对 VS2013 的残酷 hack,完全不可移植,但我很想看看我是否可以做一些工作。它可能无法解决您的问题,但我认为值得分享。因为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;
}

【讨论】:

  • 谢谢山姆。您对可移植性的看法是正确的:GCC 4.9 不知道您的std::_Bind。不过,通过一些工作,我认为这个想法可能是有效的。
  • @user2023370 It looks like its in there somehow 但它有不同的签名。您的设置也可能用一两个开关隐藏 libstdc++ 实现细节。
【解决方案2】:

std::bind 是一个黑盒子。它不支持自省(std::result_ofstd::is_bind_expression 除外)或多态性(std::placeholders 除外)。当您调用f(0) 时,它会编译为0*2+1 的本机代码。

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

如果您想以便携方式操作表达式,请查看Boost.Proto 通用表达式模板库。不过,这是很重的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-05
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多