【问题标题】:Why don't these functions decay to a function pointer?为什么这些函数不会衰减为函数指针?
【发布时间】:2020-10-07 12:11:43
【问题描述】:

我有一个类,其中包含一个要调用的函数指针,现在我遇到了一种情况,我希望该可调用函数包含一个自包含的引用/值 (lambda)。所以我创建了我的模板类来接受这样的函数指针或 lambda:

template <typename FunctionType>
class MyClass
{
public:
    MyClass(FunctionType function) : function(function) {}
    FunctionType function;
};

但似乎每次实例化此类时,编译器都会创建不同的“类型”类,如下所示:

int main()
{
    MyClass foo([]() {return 5; });
    MyClass foo2([]() {return 5; });
    MyClass foo3([]() {return 5; }); // ALL THREE OF THESE SEEM TO BE DIFFERENT TYPES
    MyClass foo4(static_cast<int(*)()> ([]() {return 5; })); // I THINK I CAN FORCE THEM TO BE THE SAME TYPES BY CASTING
    MyClass foo5(static_cast<int(*)()> ([]() {return 5; }));
    MyClass foo6(static_cast<int(*)()> ([]() {return 5; }));

    std::cout << typeid(foo).name() << '\n';
    std::cout << typeid(foo2).name() << '\n';
    std::cout << typeid(foo3).name() << '\n';
    std::cout << typeid(foo4).name() << '\n';
    std::cout << typeid(foo5).name() << '\n';
    std::cout << typeid(foo6).name() << '\n';
}

由此产生的输出是:

class MyClass<class <lambda_e39b14fd1b959adc3c33a259b5258211> >
class MyClass<class <lambda_de164f9f0bca248459ade49332a364c3> >
class MyClass<class <lambda_9fcf071b66983e924cb117ca1e77c4c6> >
class MyClass<int (__cdecl*)(void)>
class MyClass<int (__cdecl*)(void)>
class MyClass<int (__cdecl*)(void)>

由于我将创建数百或数千个这样的内容,因此我希望尽可能不要出现这种情况。我将传递给我的班级的大多数函数应该是相同的类型,除了我需要的偶尔不同的 lambda。那么每次我传递相同的函数类型时编译器都会创建不同的类型吗?如果是这样的话,它似乎效率不高。如果必须是这种情况,那么减少编译器创建的类类型数量的最佳方法是什么?我想我是通过在创建类时强制转换为函数指针来实现的,但这似乎是一种糟糕的做法。

【问题讨论】:

  • 问题是关于衰减/使用还是关于不同类型(以及可能减少此类)?帖子的正文似乎偏离了标题。
  • 其实要求每个lambda都是自己唯一的匿名类。
  • It doesn't seem very efficient if that's the case.不同类型并不一定意味着编译器会为其创建不同的代码。
  • 你是不是故意避开std::function&lt;int()&gt;
  • 请注意,使用std::function,您的MyClass 甚至不需要是模板。

标签: c++ templates lambda closures


【解决方案1】:

你可以让你的类存储一个函数指针,像这样:

template <typename Ret, typename ...Args>
class MyClass
{
public:
    MyClass(Ret (*function)(Args...)) : function(function) {}
    Ret (*function)(Args...);
};

然后您可以通过将 lambda 显式衰减到函数指针来存储它:

MyClass foo( + []() {return 5; });

然后每个函数签名只会实例化一个类(无论是 lambda 还是函数)。

这是demo

【讨论】:

  • lambda 前面的 + 是什么意思?
  • 将 lambda 衰减为函数指针是一种“技巧”(技术)。如果你不这样做,参数推导将失败。
  • 啊,我明白了,那个 + 技巧正是我正在寻找的,不错的小接触。看看当我将它用于不会衰减到指针的东西时会发生什么会很有趣,这里有一个关于它的问题,我现在正在阅读它。
  • @DanielLangr 没有对象,因为 Lambda 没有状态,如果有状态,那么 lambda 将无法转换为函数指针
  • 更准确地说,他们没有捕获任何东西,Ted 的示例没有捕获,所以尽管他们声明状态没有存储在 lambda 本身中,而是存储在静态变量中,例如这个godbolt.org/z/f9dmeh 两次都不打印 0
猜你喜欢
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
  • 2016-02-17
  • 2011-11-14
  • 2021-12-01
相关资源
最近更新 更多