编译器是否为每个lambda生成不同的类型? [英] Does the compiler generate a different type for each lambda?

查看:70
本文介绍了编译器是否为每个lambda生成不同的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


免责声明:不要在此问题中使用代码。它调用未定义的行为。问题的核心陈述是,编译器是否为每个lambda生成一个新类型,并且相应的答案仍然有效。

Disclaimer: Do not use the code in this question. It invokes undefined behaviour. The core statement of the question, whether the compiler generates a new type for each lambda, and the corresponding answer remain valid.

通过捕获获得指向lambda的函数指针,我想到了以下技巧:

To take get a function pointer to a lambda with a capture I came up with the following trick:

auto f = [&a] (double x) { return a*x; };
static auto proxy = f;
double(*ptr)(double) = [] (double x) { return proxy(x); };
// do something with ptr

我给lambda分配了一个捕获(可能是函数参数)到函数内部的静态变量,因此在其他lambda中使用它时不必捕获它。然后,另一个无捕获的lambda可以愉快地衰减到一个函数指针,该函数指针可以传递给一些共享库。

I assign the lambda with a capture (which might be a function parameter) to a static variable inside the function, so I do not have to capture it when using it in the other lambda. The other captureless lambda can then happily decay to a function pointer which I can pass to some shared library.

现在,人们可以尝试将其概括化:

Now one could attempt to generalize this:

template < typename F >
decltype(auto) get_ptr(F f)
{
  static auto proxy = f;
  return [] (auto ... args) { return proxy(args...); };
}

但是,作为 proxy 是一个静态变量,它将在每次调用该函数时被覆盖。因为它是模板,所以我认为仅当我调用相同的实例化时,它才会被覆盖,即每个实例化都有它自己的静态 proxy

However, as proxy is a static variable it will be overwritten on each call to the function. Because it is a template, I think that it will be overwritten only when I call the same instantiation, i.e. each instantiation has it's own static proxy.

尽管如此,还是可以进行以下工作:

Nevertheless, the following works:

#include <cassert>

template < typename F >
decltype(auto) get_ptr(F f)
{
  static auto proxy = f;
  return [] (auto ... args) { return proxy(args...); };
}

int main()
{
  auto f1 = [ ](double,double) { return 1; };
  auto f2 = [=](double,double) { return 2; };
  auto f3 = [&](double,double) { return 3; };
  auto f4 = [&](double,double) { return 4; };
  auto f5 = [ ](double,double) { return 5; };

  int(*p1)(double,double) = get_ptr(f1);
  int(*p2)(double,double) = get_ptr(f2);
  int(*p3)(double,double) = get_ptr(f3);
  int(*p4)(double,double) = get_ptr(f4);
  int(*p5)(double,double) = get_ptr(f5);

  assert( p1(0,0) == 1 );
  assert( p2(0,0) == 2 );
  assert( p3(0,0) == 3 );
  assert( p4(0,0) == 4 );
  assert( p5(0,0) == 5 );
}

这似乎对 get_ptr(f1) get_ptr(f5)可能会推导出相同的类型。但是,lambda是编译器生成的结构,并且似乎编译器会为每个lambda生成不同的类型,而不管以前的lambda看起来是否可以重用。

This looks suspicious as for get_ptr(f1) and get_ptr(f5) one might expect the same types to be deduced. However, lambdas are compiler generated structs and it seems as if the compiler would generate a different type for each lambda, regardless of whether previous lambdas look like they could be reused.

因此,在编译器肯定会为每个lambda生成不同类型的情况下,上述技巧对我来说将非常有用。

So the above trick would be extremely useful for me under the condition that the compiler will definitely generate a different type for each lambda. If this is not the case the generalisation of my hack is useless.

推荐答案

根据规范草案(特别是n3376), 5.1.2.3 (重点是我的)。

From the draft spec (n3376 specifically), 5.1.2.3 (emphasis mine).


lambda表达式的类型(也就是闭包对象)是一种唯一,未命名的非联盟类类型,称为闭包类型...

The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type...

这篇关于编译器是否为每个lambda生成不同的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆