Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么要设计具有唯一匿名类型的语言? 这是一直困扰我的C++ C++ lambda表达式的一个特性:C++ lambda表达式的类型是唯一的和匿名的,我根本无法写下来。即使我创建了两个语法完全相同的lambda,结果类型也被定义为不同的。结果是,a)lambda只能传递给允许将编译时、无法描述的类型与对象一起传递的模板函数,b)lambda只有在通过std::function进行类型擦除后才有用 当然,但是这只是C++的方式,我准备把它写出来,只是语言的一个令人讨厌的特征。然而,我刚刚了解到,Rust的作用似乎是相同的:每个Rust函数或lambda都有一个唯一的匿名类型。现在我想知道:为什么_C++_Types_Rust_Language Design - Fatal编程技术网

为什么要设计具有唯一匿名类型的语言? 这是一直困扰我的C++ C++ lambda表达式的一个特性:C++ lambda表达式的类型是唯一的和匿名的,我根本无法写下来。即使我创建了两个语法完全相同的lambda,结果类型也被定义为不同的。结果是,a)lambda只能传递给允许将编译时、无法描述的类型与对象一起传递的模板函数,b)lambda只有在通过std::function进行类型擦除后才有用 当然,但是这只是C++的方式,我准备把它写出来,只是语言的一个令人讨厌的特征。然而,我刚刚了解到,Rust的作用似乎是相同的:每个Rust函数或lambda都有一个唯一的匿名类型。现在我想知道:为什么

为什么要设计具有唯一匿名类型的语言? 这是一直困扰我的C++ C++ lambda表达式的一个特性:C++ lambda表达式的类型是唯一的和匿名的,我根本无法写下来。即使我创建了两个语法完全相同的lambda,结果类型也被定义为不同的。结果是,a)lambda只能传递给允许将编译时、无法描述的类型与对象一起传递的模板函数,b)lambda只有在通过std::function进行类型擦除后才有用 当然,但是这只是C++的方式,我准备把它写出来,只是语言的一个令人讨厌的特征。然而,我刚刚了解到,Rust的作用似乎是相同的:每个Rust函数或lambda都有一个唯一的匿名类型。现在我想知道:为什么,c++,types,rust,language-design,C++,Types,Rust,Language Design,所以,我的问题是: 从语言设计者的角度来看,在语言中引入唯一匿名类型的概念有什么好处?首先,没有捕获的lambda可以转换为函数指针。因此,它们提供了某种形式的泛型 现在为什么带有捕获的lambda不能转换为指针?因为函数必须访问lambda的状态,所以这个状态需要作为函数参数出现。 p> C++ +lambdas需要不同类型的不同操作,因为C++静态绑定。它们只是可复制/移动的,所以大多数情况下不需要命名它们的类型。但这些都是一些实现细节 我不确定C#lambda是否有类型,因为它们是“匿名函

所以,我的问题是:

从语言设计者的角度来看,在语言中引入唯一匿名类型的概念有什么好处?

首先,没有捕获的lambda可以转换为函数指针。因此,它们提供了某种形式的泛型

现在为什么带有捕获的lambda不能转换为指针?因为函数必须访问lambda的状态,所以这个状态需要作为函数参数出现。 p> C++ +lambdas需要不同类型的不同操作,因为C++静态绑定。它们只是可复制/移动的,所以大多数情况下不需要命名它们的类型。但这些都是一些实现细节

我不确定C#lambda是否有类型,因为它们是“匿名函数表达式”,它们会立即转换为兼容的委托类型或表达式树类型。如果是,它可能是一个不可命名的类型

C++还有匿名结构,其中每个定义都指向一个唯一的类型。这里的名称不是不可命名的,就标准而言,它根本不存在

C#有,它小心地禁止从它们定义的范围中逃脱。该实现也为这些对象提供了一个唯一的、不可命名的名称

使用匿名类型向程序员发出信号,表示他们不应该在其实现内部闲逛

旁白:

您可以为lambda的类型命名

auto foo = []{}; 
using Foo_t = decltype(foo);
如果没有任何捕获,可以使用函数指针类型

void (*pfoo)() = foo;
(补充了Caleth的答案,但太长了,无法加入评论。)

lambda表达式只是匿名结构(伏地魔类型,因为你不能说出它的名字)的语法糖

您可以在以下代码片段中看到匿名结构和lambda匿名性之间的相似性:

#include <iostream>
#include <typeinfo>

using std::cout;

int main() {
    struct { int x; } foo{5};
    struct { int x; } bar{6};
    cout << foo.x << " " << bar.x << "\n";
    cout << typeid(foo).name() << "\n";
    cout << typeid(bar).name() << "\n";
    auto baz = [x = 7]() mutable -> int& { return x; };
    auto quux = [x = 8]() mutable -> int& { return x; };
    cout << baz() << " " << quux() << "\n";
    cout << typeid(baz).name() << "\n";
    cout << typeid(quux).name() << "\n";
}
#包括
#包括
使用std::cout;
int main(){
结构{intx;}foo{5};
结构{intx;}bar{6};

CUT< P> lambdas不只是函数,它们是函数和状态。因此C++和Rig都将它们作为对象调用,在C++中调用操作符(<代码>操作程序)> />代码,3代码> FN*<代码>生锈特性。

基本上,<代码> [a] {C++ +DugARs中的A+1;} /Cube >类似于

struct __SomeName {
    int a;

    int operator()() {
        return a + 1;
    }
};
然后使用使用lambda的
\uu SomeName
实例

生锈时,
|a+1
生锈时会脱胶成类似的东西

struct __SomeName {
    int a;

    int operator()() {
        return a + 1;
    }
};
{
结构uu SomeName{
a:i32,
}
为uuu SomeName执行一次{
类型输出=i32;
extern“rust call”fn call_一次(self,args:())->self::Output{
自我评价a+1
}
}
//以及必要时的FnMut和Fn
__SomeName{a}
}
这意味着大多数lambda必须具有不同的类型

现在,我们有几种方法可以做到这一点:

  • 使用匿名类型,这是两种语言都实现的。这样做的另一个结果是,所有lambda都必须具有不同的类型。但对于语言设计者来说,这有一个明显的优势:lambda可以简单地使用语言中其他已经存在的较简单部分进行描述。它们只是已经存在的语法糖语言的点点滴滴。
  • 用一些特殊的语法来命名lambda类型:但是,由于lambda已经可以与C++中的模板或泛型和 fn*/COD>字符一起使用,所以这不是必要的。语言都不会强迫您使用擦除lambda来使用它们(在C++中使用<代码> STD::函数< />代码>或<代码> box <代码>生锈)。
还请注意,这两种语言都同意,不捕获上下文的普通lambda可以转换为函数指针


使用简单的特征描述语言的复杂特征是很常见的。例如C++和RISE都有循环的范围,它们都把它们描述为其他特征的语法糖。 C++定义

for(自动&&[first,second]:mymap){
//使用第一个和第二个
}
等同于

{

    init-statement
    auto && __range = range_expression ;
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) {

        range_declaration = *__begin;
        loop_statement

    }

} 
锈决定了一切

{}中的

等同于

{

    init-statement
    auto && __range = range_expression ;
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) {

        range_declaration = *__begin;
        loop_statement

    }

} 
let result=match::std::iter::IntoIterator::into_iter(){
mut iter=>{
环路{
let=match::std::iter::Iterator::next(&mut-iter){
::std::option::option::Some(val)=>val,
::std::option::option::None=>中断
};
SemiExpr();
}
}
};
对于人类来说,它们似乎更复杂,但对于语言设计者或编译器来说都更简单

为什么要设计具有唯一匿名类型的语言

因为在某些情况下,名称是不相关的,没有用处,甚至没有反作用。在这种情况下,抽象出它们的存在是有用的,因为它减少了名称污染,解决了计算机科学中两个难题之一(如何命名事物)。出于同样的原因,临时对象是有用的

兰姆达

唯一性不是一个特殊的lambda对象,甚至对于匿名类型来说也不是一个特殊的对象
int counter()
{
    static int count = 0;
    return count++;
}

template <typename FuncT>
void action(const FuncT& func)
{
    static int ct = counter();
    func(ct);
}

...
for (int i = 0; i < 5; i++)
    action([](int j) { std::cout << j << std::endl; });

for (int i = 0; i < 5; i++)
    action([](int j) { std::cout << j << std::endl; });
// one.cpp
struct A { int operator()(int x) const { return x+1; } };
auto b = [](int x) { return x+1; };
using A1 = A;
using B1 = decltype(b);

extern void foo(A1);
extern void foo(B1);
// two.cpp
struct A { int operator()(int x) const { return x + 1; } };
auto b = [](int x) { return x + 1; };
using A2 = A;
using B2 = decltype(b);

void foo(A2) {}
void foo(B2) {}
auto a = [](){};  // a has type $_0
auto b = [](){};  // b has type $_1
auto f(int x) {
    return [x](int y) { return x+y; };  // f(1) and f(2) both have type $_2
} 
auto g(float x) {
    return [x](int y) { return x+y; };  // g(1) and g(2) both have type $_3
} 
template<class T> void foo(decltype(T())) {}
template void foo<int>(int);  // _Z3fooIiEvDTcvT__EE, not _Z3fooIiEvT_
auto f(int x) {
    return [x](int y) { return x+y; };
}

// Give the type an alias, so I can refer to it within this translation unit
using AdderLambda = decltype(f(0));

int of_one(AdderLambda g) { return g(1); }

int main() {
    auto f1 = f(1);
    assert(of_one(f1) == 2);
    auto f42 = f(42);
    assert(of_one(f42) == 43);
}
int add1(int x) { return x + 1; }
int add2(int x) { return x + 2; }
static_assert(std::is_same_v<decltype(add1), decltype(add2)>);
auto add3 = [](int x) { return x + 3; };
auto add4 = [](int x) { return x + 4; };
static_assert(not std::is_same_v<decltype(add3), decltype(add4)>);
template<class T>
int default_construct_and_call(int x) {
    T t;
    return t(x);
}

assert(default_construct_and_call<decltype(add3)>(42) == 45);
assert(default_construct_and_call<decltype(add4)>(42) == 46);
let f: __UniqueFunc042 = || { ... };  // definition of __UniqueFunc042 (assume it has a nontrivial closure)

/* ... intervening code */

let g: __UniqueFunc042 = /* some expression */;
g();
let q = if some_condition { f } else { || {} };  // ERROR: type mismatch
let f2 = &f as &dyn Fn();  // upcast
let q2 = if some_condition { f2 } else { &|| {} };  // OK
let g2: &dyn Fn() = /*expression */;
fn h<F: Fn()>(f: F);
h::<__UniqueFunc042>(f);
h::<&Fn()>(f);