在不使用 option-Wpedantic的情况下,启用 c++11 的编译器允许在 lambda 表达式中使用默认值。
对于这样的表达式,您可以使用std::function指定所有参数类型的类型,包括默认指定的参数。
但是,当使用带有 auto 关键字的自动类型推断时,lambda 表达式采用特定类型,例如main()::<lambda(int)>,其中括号中的值是传递给表达式的参数的类型。并且这些值总是被指定,不管它们是否有默认值(这通常是合乎逻辑的)。
下面是一个代码示例。
#include <functional>
#include <iostream>
void f1(std::function<int()> lambda)
{
if (lambda)
{
std::cout << lambda() << std::endl;
}
}
void f2(std::function<int(int)> lambda)
{
if (lambda)
{
std::cout << lambda(1) << std::endl;
}
}
int main()
{
auto lambda1 = [](int a = 3) -> int
{
return a;
};
f1(lambda1);
f2(lambda1);
std::function<int()> lambda2 = []()
{
return 1;
};
std::function<int(int)> lambda3 = [](int a)
{
return a;
};
f1(lambda2);
//f2(lambda2); // Очевидно несоответствие типов
//f1(lambda3); // Очевидно несоответствие типов
f2(lambda3);
}
在代码示例中,类型main()::<lambda(int)>被强制转换为std::function<int()>. 我没有足够的知识来理解为什么编译器不会对类型不匹配发誓。请帮我解释一下。
以及相关问题。
我可以明确指定一种类型,比如自动推断的类型吗?
我可以告诉编译器不允许这种类型的转换吗?
由 lambda 表达式生成的闭包对象的类型独立于 lambda 参数,并且不由 lambda 参数决定。默认参数的存在或不存在在这里没有任何作用。每个 lambda 表达式都会产生一个新的唯一类型——这就是你需要知道的关于闭包对象的类型。即使两个 lambda 表达式完全相同,它们仍然会以任何方式彼此不相关的唯一类型结束。在您的示例中,您在此类型的内部名称中看到了参数列表的一些提示,这只不过是您使用的实现的一个装饰性功能。但是,您在编译器消息中看到的闭包对象类型的文本描述并不是对实际类型的详尽描述。
例如,响应
您将收到来自 GCC 的诊断消息,例如
如您所见,引号中的类型描述完全相同。但是,它们是不同的、不相关的类型。
因此,在使用 lambda 表达式时,根本谈不上“类型匹配”:所有类型的闭包对象都是唯一的,并且从不对应任何东西。
该类
std::function<>建立在类型擦除的原则之上,即 事实上,它是一个更加专业化的类比std::any。此类的构造函数是模板化的(参见此处的第 5 点)——它没有也不能在语言的底层类型系统级别进行任何“类型匹配”检查。在语言的基本类型系统级别,这个构造函数可以接受任何类型作为输入。通过 SFINAE 等技术,任何检查都已经在库实现的级别上挂在此构造函数上。初始化视图时,会检查Callable
std::function<F> sf = f;要求:对象必须是Callable类型的函数。检查此要求,它适用于您的示例。fF例如,闭包对象
lambda1是Callable和 asint()和 asint(int)。因此,您可以将它用于初始化std::function<int()>和初始化std::function<int(int)>。明显不是。闭包对象的类型是实现定义的,没有明确指定它的语法。您只能在它已经显示后隐式地“指定”它 - 通过
decltype对已经存在的对象应用闭包编译器与它无关。您正在处理纯库功能:
std::function<>. 只要您使用 classstd::function<>,它就会按照语言规范的要求运行。禁止在 lambda 表达式中指定默认参数被认为是一个缺陷,并在标准的后续版本中被取消。因此,编译器对此类操作持保留态度。lambda 表达式的类型是匿名的,因此将显式引用它,或者您不能以任何其他方式显式指定它。它
std::function有一个隐式模板构造函数,可以接受适当的 lambda 表达式对象,因此您无能为力。std::function