当前位置: 首页 > 知识库问答 >
问题:

C使用lambda进行隐式构造函数调用,期望函数指针

范金鑫
2023-03-14

我试图从lambda函数隐式构造一个对象。对象的构造函数将函数指针作为参数。但是代码[1]没有编译消息:

6 : <source>:6:5: note: candidate constructor not viable: no known conversion from '(lambda at /tmp/compiler-explorer-compiler117117-54-dfxyju.lkw98/example.cpp:22:14)' to 'Bar' (aka 'bool (*)()') for 1st argument
    Foo(Bar b) : m_b{b} {}

但是标准规定lambda函数可以隐式转换为具有相同参数和返回类型[2]的函数指针。这应该适用于这里,因此我希望构造函数是可调用的。

那么为什么代码不能编译呢?谢谢你的解释!

[1]代码示例:

using Bar = bool(*)();

class Foo
{
public:
    Foo(Bar b) : m_b{b} {}
private:
    Bar m_b;
};

int main()
{   
    // working
    Foo f1 ( [](){ return true; });
    Foo f2 = Bar( [](){ return true; });

    // working implicit conversion
    bool(*tmp)() = []() { return true; };
    Foo f3 = tmp;

    // not working
    Foo f4 = [](){ return true; };

    return 0;
}

https://godbolt.org/g/QE4v1Z

[2]C 14标准在第5.1节中规定。2.建议:

没有lambda捕获的lambda表达式的闭包类型具有一个公共非虚拟非显式const转换函数,该函数指向与闭包类型的函数调用运算符具有相同参数和返回类型的函数指针。此转换函数返回的值应为函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果。

这意味着lambda应该可以隐式(非显式)转换为函数指针。

测试:

  • clang5.0.0-std=c 14
  • MSVC14.12 /permissive-

共有1个答案

羊禄
2023-03-14

是,它可以隐式转换为函数指针;这就是为什么bool(*tmp)(=[](){return true;} 工作。关键是在一个隐式转换序列中,只允许一个用户定义的转换。

隐式转换序列按以下顺序组成:

  1. 零或一个标准转换序列
  2. 零或一个用户定义的转换
  3. 零或一个标准转换序列

当考虑构造函数或用户定义的转换函数的参数时,只允许一个标准转换序列(否则用户定义的转换可能被有效地链接)。

对于Foo f4 = [](){ 返回true;};,这是复制初始化,lambda必须通过lambda的用户定义转换函数转换为函数指针,然后通过Foo,需要两个用户定义的转换,但不允许。

顺便说一句:

>

  • Foo f1([](){return true;})可以工作,因为对于直接初始化,Foo的构造函数将被直接调用;lambda被转换为函数指针,然后作为参数传递给构造函数,这很好。

    Foo f2=Bar([](){return true;}) 之所以有效,是因为lambda显式转换为函数指针,而函数指针稍后隐式转换为Foo

    bool(*tmp)() = []() { 返回true;}; Foo f3=tmp;工作,因为lambda被隐式地转换为函数指针为tmp,然后tmp被转换为Foo;仅对于任何一个隐式转换序列,都需要一个用户定义的转换,然后就可以了。

    foof5=[](){返回true;}之所以工作,是因为运算符导致lambda转换为函数指针,这意味着对于[](){return true;}您将获得类型为bool(*)()的函数指针,然后故事与f2相同。

  •  类似资料:
    • 我有一个 Scala 类,它使用 Apache Spark 中的 MR 作业返回输入类型 IN 的最大值。如果我从Scala调用它,这个类工作正常,它的工作原理如下: 现在我想让它也可以从java中调用,但是我在传递隐式参数时遇到了一些困难。我知道隐式参数可以通过在Java中将它们追加到参数列表中来传递,但是隐式参数是在Scala中。因此,我正在努力做到以下几点: 然后可以从java调用: 我尝试

    • 问题内容: 我想为MySortedSet调用一个构造函数,该构造函数将Comparator c作为参数。我该如何修改呢? 问题答案: 如果要传递其他捕获的值作为参数,则不能使用方法引用。您将不得不使用lambda表达式来代替: =>

    • 上面写着编译错误 Employee::new、1L、“”、“ 无法解析构造函数。

    • 主要内容:1、实例构造函数,2、静态构造函数,3、私有构造函数在 C# 中,构造函数就是与类(或结构体)具有相同名称的成员函数,它在类中的地位比较特殊,不需要我们主动调用,当创建一个类的对象时会自动调用类中的构造函数。在程序开发的过程中,我们通常使用类中的构造函数来初始化类中的成员属性。 C# 中的构造函数有三种: 实例构造函数; 静态构造函数; 私有构造函数。 1、实例构造函数 构造函数是类中特殊的成员函数,它的名称与它所在类的名称相同,并且没有返回值。当

    • 主要内容:构造函数的重载,默认构造函数在 C++中,有一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户显式调用(用户也不能调用),而是在创建对象时自动执行。这种特殊的成员函数就是 构造函数(Constructor)。 在《 C++类成员的访问权限以及类的封装》一节中,我们通过成员函数 setname()、setage()、setscore() 分别为成员变量 name、age、score 赋值,这样做虽然有效,但显得有点

    • C++ 类 & 对象 类的构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。 下面的实例有助于更好地理解构造函数的概念:#include <iostream> using namespace std; class Line { public: v