【问题标题】:Does C++11 have any support for local functions?C++11 是否支持本地函数?
【发布时间】:2011-11-09 19:58:24
【问题描述】:

既然 C++ 中有 lambda,我不能声明一个本地函数似乎真的很愚蠢......

例如:

我可以在函数体中声明一个类型,甚至将它初始化为一个值表。但我无法创建一个适用于该数据类型的辅助函数 - 因为我无法在函数中声明函数,也无法在函数之外引用该数据类型,因为它仅在该范围内可用。

有时将数据类型从函数中提取出来并在那里定义我的数据类型和辅助函数(本地文件范围)非常简单 - 但有时它并不是一个真正合理的解决方案 - 例如当使用引用局部范围变量(或 this)的内联 lambda 初始化表时。

知道对本地函数的支持是否即将到来,是否已经定义,或者为什么编译器编写者难以实现它们因此不是标准的一部分?

【问题讨论】:

  • 本地函数会为您提供哪些使用 auto + lambda 无法轻松实现的功能?
  • 局部函数比局部变量更难实现,尽管可能与实现 lambda 的方式相同。
  • 在完整的 C++11 中可能什么都没有?虽然不确定是什么广告。声明一个 lambda 已经超过了一个命名的本地...似乎编译器可以处理一个,它可以处理另一个,不是吗?而且我认为规则应该是相似的——除了你不能用本地函数捕获任何东西,所以是的,更简单......
  • "虽然不确定声明 lambda 对命名的本地函数有什么好处..." 主要优点是它是合法的/受支持的,而命名的本地函数不是。 ;-]
  • @Steve : "将捕获的 lambda 转换为普通函数指针的能力" 老实说,这听起来很可怕。 ;-/

标签: c++ c++11


【解决方案1】:

没有局部函数,但是没有闭包它们就没有那么有用了,即访问局部变量。在任何情况下,您都可以很容易地用 lambda 模拟本地函数。

代替:

void foo(int x)
{
    struct S
    {
         //...
    };
    int Twice(int n, S *s) //Not allowed
    {
        return 2*n;
    }

    S s;
    int x = Twice(3, &s);
    //...
}

做:

void foo()
{
    struct S
    {
         //...
    };
    auto Twice = [](int x, S *s) -> int //Cool!
    {
        return 2*x;
    }; //Twice is actually a variable, so don't forget the ;


    S s;
    int x = Twice(3, &s);
    //...
}

如果捕获集为空,([]) 甚至可以将其转换为普通的函数指针,就像真正的函数一样!

和 AFAIK 一样,lambda 可以毫无问题地使用本地类型。但是,当然,该结构中的公共静态成员函数也应该可以正常工作。

作为附加说明,与您的问题间接相关,C++11 中允许使用本地类型实例化模板(这在 C++98 中是禁止的):

void foo()
{
    struct S {};
    std::vector<S> vs; //error in C++98, ok in C++11
}

【讨论】:

    【解决方案2】:

    C++11 中没有本地函数。

    但是有 lambdas。

    而且你的本地类型可以有成员函数!

    【讨论】:

      【解决方案3】:

      不,您不能这样做,但 lambda 肯定比纯本地函数更有用,因为它们还可以选择性地捕获状态?它们既可以匿名使用,也可以分配给一个自动变量,并在任意多的地方使用。

      以前的另一个主要解决方法(尤其是在使用标准库算法时)是定义一个具有合适 operator() 实现的本地仿函数结构。您也可以使用此方法捕获状态,但需要更多代码才能执行此操作。 Lambda 是实现相同目标的一种非常简洁的方式。

      【讨论】:

        【解决方案4】:

        这相当复杂,但您可以在本地结构类型中创建本地函数:

        int quadruple(int x) {
          struct Local {
            static int twice(int val) { return val * 2; }
          };
          return Local::twice(Local::twice(x));
        }
        

        请注意,本地函数无法访问局部变量 - 为此您需要一个 lambda。但是,它对于局部重载很有用:

        template <typename T>
        T mod(T x, T y) {
          struct Local {
            static int local(int x, int y) { return x % y; }
            static double local(double x, double y) { return std::fmod(x, y); }
          };
          return Local::local(x, y);
        }
        

        【讨论】:

          【解决方案5】:

          局部函数绝对不难实现,它们至少在 1968 年的 Pascal 中就出现了,甚至可能更早。它们在 GCC 中作为 C 扩展实现。

          传递嵌套函数的地址有点复杂,它通常包括设置一段代码(trampoline),它首先设置静态链接/显示/用于访问局部变量的任何机制,然后执行实际功能代码。蹦床驻留在堆栈上,这意味着堆栈必须是可执行的,因此具有通常的安全隐患。

          C++ 委员会是否考虑并拒绝了嵌套函数是任何人的猜测,但我建议,虽然实现起来并不困难,但嵌套函数的好处并不值得付出努力。

          【讨论】:

            猜你喜欢
            • 2018-03-22
            • 2018-10-17
            • 2013-10-15
            • 2023-03-08
            • 1970-01-01
            • 2018-12-10
            • 2019-04-27
            • 2012-01-08
            • 2019-03-24
            相关资源
            最近更新 更多