【问题标题】:C++11 inline lambda functions without template没有模板的 C++11 内联 lambda 函数
【发布时间】:2014-01-28 22:22:51
【问题描述】:

我想将 lambda 函数作为回调传递给另一个函数:

void test(const std::function<void()> fn){
    fn();
}

它工作正常,一切正常。但。无论我使用多高的编译器优化级别,它都不会内联它:
proof

当我玩了一段时间后,我发现使用模板 - 它变成了内联:

template<typename T>     
void test2(T fn){
     fn();
}

proof_2

那么...有没有办法让它在没有模板的情况下内联?以及为什么它与模板声明内联?只有函数类型作为模板参数传递,而不是函数本身。

【问题讨论】:

  • std::function 是一个类型擦除类(很可能会通过函数指针间接调用 fn)。通过std::function 捕获 lambda 几乎肯定会扼杀你内联它的机会。
  • @Alex 但“typename T”不会扣除相同的 std::function 吗?
  • @tower120 不,lambda 表达式的类型不是std::function。它是“未命名的、唯一的、非联合类类型,称为闭包类型”。参见 ISO C++ §5.1.2/3。
  • @Alex 您可以使用decltype 或模板参数推导来获取类型,或auto 间接使用它。我认为没有其他办法。
  • @Alex 你当然不能使用auto 作为参数类型,但是decltype is just fine。当然,这意味着你只能传入那个特定的 lambda - 在实践中并不真正可用。

标签: c++ c++11 lambda


【解决方案1】:

简短回答:不,如果没有模板(在一般情况下),您将无法完成这项工作。原因是源代码中的每个 lambda 表达式都会为该 lambda 闭包生成一个 唯一类型。 Proof:

auto f1 = [] { return 1; };
auto f2 = [] { return 1; };
static_assert(!std::is_same<decltype(f1), decltype(f2)>::value, "He's wrong");

因此,要接受任意闭包,您要么必须使用模板,要么必须使用类型擦除包装器(例如std::function)。当然,类型擦除依赖于运行时多态性,因此它不适合内联。

您可能完成这项工作的唯一方法是使用无状态 lambda(无捕获),它具有到函数指针的隐式转换。让您的算法将参数作为指向函数的指针,并希望优化器看得足够深以内联调用。换句话说,把函数改成这样:

void test(void (*fn)()) {
    fn();
}

【讨论】:

  • 我的例子不是无状态的吗?它不捕获任何东西。
  • @tower120 是的。因此,如果您更改函数签名以获取指向函数的指针而不是 std::function,它应该可以工作。注意:答案已编辑
  • @tower120 是的,它是无状态的,所以如果你的编译器用void test3(void (*fn)()){ fn(); }内联调用
  • 它在简单的情况下有效,但在更真实的情况下 - 没有tinyurl.com/qzeoher。您可以将此添加到您的答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
相关资源
最近更新 更多