C++ 通用lambdas:语法糖还是不糖?

C++ 通用lambdas:语法糖还是不糖?,c++,lambda,syntactic-sugar,c++14,generic-lambda,C++,Lambda,Syntactic Sugar,C++14,Generic Lambda,C++14泛型lambda是给语言带来了真正的改进,还是它们是一种语法糖?是否存在以下情况: [](auto param1, auto param2, /* ... */ auto paramN) { return /* ... */; } 不可替代 template <typename Type1, typename Type2, /* ... */ typename TypeN> auto foo(Type1&& param1, Type2&&a

C++14泛型lambda是给语言带来了真正的改进,还是它们是一种语法糖?是否存在以下情况:

[](auto param1, auto param2, /* ... */ auto paramN)
{
    return /* ... */;
}
不可替代

template <typename Type1, typename Type2, /* ... */ typename TypeN>
auto foo(Type1&& param1, Type2&& param2, /* ... */ TypeN&& paramN)
{
    return  /* ... */;
}
模板
自动foo(Type1&¶m1、Type2&¶m2、/*…*/TypeN&¶mN)
{
返回/*…*/;
}

结构栏
{
样板
自动运算符()
{
返回/*…*/;
}
};
?


提供了非常有趣的链接,说明了通用lambdas的强大功能:

  • :用于表达式元编程的异构组合器()

C++14泛型lambda是否给语言带来了真正的改进

或者它们是一种语法糖

你似乎暗示句法上的糖分并不是语言的真正进步。请记住,语言本身就是语法糖。您可以用机器代码编写所有内容:)

C++14泛型lambda是否给语言带来了真正的改进

或者它们是一种语法糖

你似乎暗示句法上的糖分并不是语言的真正进步。请记住,语言本身就是语法糖。您可以在Lambdas上用机器代码编写所有内容:)

一般来说:

有些人认为这“真的很整洁!”其他人则认为这是一种编写晦涩难懂的危险代码的方式。依我看,两者都是对的比亚恩·斯特罗斯图普

我认为这是一个如何使用lambda的问题。作为一个小型的局部闭包函数,您可以使用它来改进对函数的处理,函数将函数对象作为参数(如
std::sort
),我实际上没有看到一个示例,在这个示例中,通用lambdas会增加任何好处

如果你用C++来对Haskell进行编码,那么它会增加一些好处,但是我看到过很多代码示例,其中对象生存期至少部分被忽略了。所以我不认为这会增加好处

让我解释一下:

void foo(std::vector<int>& v)
{
    std::sort(v.begin(), v.end(), [](int i, int j) { return (i < j); });
}
这将使事情变得复杂,因为您必须确保返回的对象是有效的。这可能会导致荒谬的情况(例如,销毁后短时间呼叫)。我的经验是,在编写这样一个没有lambda的构造之前,程序员会三思而后行

因此,如果只在本地将它们用作辅助函数,则不需要泛型,因为所有类型都是明确的

我想我是那些认为可以用lambda编写危险的晦涩代码的人之一。

通常在lambda上:

有些人认为这“真的很整洁!”其他人则认为这是一种编写晦涩难懂的危险代码的方式。依我看,两者都是对的比亚恩·斯特罗斯图普

我认为这是一个如何使用lambda的问题。作为一个小型的局部闭包函数,您可以使用它来改进对函数的处理,函数将函数对象作为参数(如
std::sort
),我实际上没有看到一个示例,在这个示例中,通用lambdas会增加任何好处

如果你用C++来对Haskell进行编码,那么它会增加一些好处,但是我看到过很多代码示例,其中对象生存期至少部分被忽略了。所以我不认为这会增加好处

让我解释一下:

void foo(std::vector<int>& v)
{
    std::sort(v.begin(), v.end(), [](int i, int j) { return (i < j); });
}
这将使事情变得复杂,因为您必须确保返回的对象是有效的。这可能会导致荒谬的情况(例如,销毁后短时间呼叫)。我的经验是,在编写这样一个没有lambda的构造之前,程序员会三思而后行

因此,如果只在本地将它们用作辅助函数,则不需要泛型,因为所有类型都是明确的


我想我是那些认为可以用lambda编写危险的晦涩代码的人之一。

对于C++11的非泛型lambda表达式,可以执行一个简单的翻译:

void foo()
{
    int i = 42; int j = 22;
    auto f = [i, &j](int k) { return i + j + k };
    // proceed to use f
 }
例如:

void foo()
{
    int i = 42; int j = 22;
    struct {
        int i; int& j;
        // can't deduce return type
        int operator()(int k) const
        { return i + j + k; }
    } f { i, j };
    // proceed to use f
}
对于C++14的通用lambda表达式,它并不那么简单。假设这次我们使用的是
autof=[i,&j](autok){returni+j+k;}
。然后我们必须生成以下呼叫接线员:

template<typename T>
auto operator()(T k) const { return i + j + k; }
模板
自动运算符()(Tk)常量{返回i+j+k;}
问题是我们无法在函数范围内定义模板(这一限制也称为无本地模板)。因此,我们必须将闭包类型定义从封闭函数移出到命名空间范围(在过程中给它一个名称),然后使用
closure\u type f{i,j}。顺便说一句,这意味着我们必须给类及其运算符某种形式的链接,而函数局部定义没有链接


因此,从某种意义上说,通用lambda表达式为我们提供了有限版本的本地函数模板。

对于C++11的非通用lambda表达式,可以执行一个简单的转换:

void foo()
{
    int i = 42; int j = 22;
    auto f = [i, &j](int k) { return i + j + k };
    // proceed to use f
 }
例如:

void foo()
{
    int i = 42; int j = 22;
    struct {
        int i; int& j;
        // can't deduce return type
        int operator()(int k) const
        { return i + j + k; }
    } f { i, j };
    // proceed to use f
}
对于C++14的通用lambda表达式,它并不那么简单。假设这次我们使用的是
autof=[i,&j](autok){returni+j+k;}
。然后我们必须生成以下呼叫接线员:

template<typename T>
auto operator()(T k) const { return i + j + k; }
模板
自动运算符()(Tk)常量{返回i+j+k;}
问题是我们无法在函数范围内定义模板(这一限制也称为无本地模板)。因此,我们必须将闭包类型定义从封闭函数移出到命名空间范围(在过程中给它一个名称),然后使用
closure\u type f{i,j}。顺便说一句,这意味着我们必须给类及其运算符某种形式的链接,而函数局部定义没有链接


因此,在某种意义上,通用lambda表达式为我们提供了有限版本的局部函数模板。

参见(也)您可以询问非通用lambda的相同问题。最初
lambda
是语法糖;为了方便起见,你的曲