Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.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++ 初始化和lambda类型参数_C++_C++11_Constructor_Lambda_Initialization - Fatal编程技术网

C++ 初始化和lambda类型参数

C++ 初始化和lambda类型参数,c++,c++11,constructor,lambda,initialization,C++,C++11,Constructor,Lambda,Initialization,我有这样一个实用类: struct Atreturn { std::function<void()> funcdestr; Atreturn( std::function<void()> fd ): funcdestr(fd) {} ~Atreturn() { funcdestr(); } }; 复制初始化构造函数调用: Atreturn hook ( [something]() { DestroySomething(something); }

我有这样一个实用类:

struct Atreturn
{
    std::function<void()> funcdestr;
    Atreturn( std::function<void()> fd ): funcdestr(fd) {}
    ~Atreturn() { funcdestr(); }
};
  • 复制初始化构造函数调用:

    Atreturn hook ( [something]() { DestroySomething(something); } );
    
    Atreturn hook = [something]() { DestroySomething(something); };
    
    Atreturn hook { [something]() { DestroySomething(something); }};
    
  • 直接列表初始化构造函数调用:

    Atreturn hook ( [something]() { DestroySomething(something); } );
    
    Atreturn hook = [something]() { DestroySomething(something); };
    
    Atreturn hook { [something]() { DestroySomething(something); }};
    
  • 现在的问题是:据我所知,方法#1和#2应该被允许,因为它们在理论上是相同的,前提是构造函数中没有显式的,而#3不应该被允许,因为这种语法阻止了转换(如果您尝试
    int{2.1}
    ,至少对
    int
    是这样)

    但是,GCC4.9允许方法#1和#3,但不允许方法#2(并表示
    从“…::”转换为请求的非标量“Atreturn”类型
    )。这听起来很疯狂,因为通常只有当您有显式构造函数时才会发生。谁能解释一下,为什么

    另外,让我把这个问题说得更清楚:我需要一些不太笨拙的语法来初始化这个Atreturn对象,至少不需要额外的大括号或圆括号。问题在于,当参数为C++11 lambda时,具有自动缩进功能的编辑器在正确的重新缩进方面存在问题。所以我需要一些语法,可以表示为:

     Atreturn BLAH BLAH BLAH [something]() { DestroySomething(something); };
    
    而不应允许使用#3,因为这种语法会阻止转换(如果尝试int{2.1},至少int是这样)

    那不太对。规则是不允许缩小转换范围。允许进行其他类型的转换
    int{2.1}
    是一种缩小的转换,因为它修改了值,失去了精度
    int{2.0}
    不是缩小转换,因为该值没有更改

    #2失败的原因是它需要两个隐式的用户定义转换,这是被禁止的

    从概念上讲,副本初始化包括:

    Atreturn hook = []() {};
    
    相当于:

    Atreturn hook = Atreturn([]() {});
    
    (除了它不能调用“显式”构造函数,并且允许编译器删除副本)

    这意味着首先lambda必须隐式转换为
    函数
    ,然后必须隐式转换为
    Atreturn
    。这两种转换都是“用户定义的转换序列”,这意味着它们调用构造函数,而不是像
    int
    long
    这样的内置转换,标准规定隐式转换序列不能包含多个用户定义的转换

    问题实际上与lambdas无关,您可以演示完全相同的错误,如下所示:

    struct L { };
    struct F { F(L) { } };
    struct A { A(F) { } };
    A a = L();
    
    l.cc:4:9: error: conversion from ‘L’ to non-scalar type ‘A’ requested
     A a = L();
             ^
    
    同样,问题是隐式转换序列
    L->F->A
    涉及两个用户定义的转换,这是被禁止的

    我不太赞同你想要修改代码以帮助自动缩进的问题——代码不应该被修改以适合有缺陷的编辑器。但是,另一个选项是添加一个模板构造函数,它接受任何可以转换为
    std::function
    的内容,例如

    struct Atreturn
    {
      using func_type = std::function<void()>;
      template<typename T,
               typename Requires = decltype(func_type(std::declval<T&&>())>
        Atreturn(T t) : funcdestr(std::move(t)) { }
      ...
    };
    
    struct Atreturn
    {
    使用func_type=std::function;
    模板
    Atreturn(T):functdesr(std::move(T)){
    ...
    };
    

    这将允许lambda直接转换为
    Atreturn
    ,而不需要先隐式转换为
    函数。

    (还添加复制列表初始化构造:
    Areturn hook={…}
    ?)这与方法#3相同,这在C++11中是可选的。#1和#2不相同。如果右边的类型是
    Atreturn
    ,它们会是一样的,但它不是。是的,
    =
    是可选的,但是直接列表初始化(没有
    =
    )和复制列表初始化(有
    =
    )不一样。“请关注问题”他们关注的是问题,指出您对所问语法的基本误解。Lambda到
    函数
    是很好的,但是您从哪里看到需要将其转换为
    Atreturn
    ?带有等号的初始化不应该使用带有该类型参数的单参数构造函数吗?@Ethouris No、直接初始化(No
    =
    )和复制初始化(with
    =
    )是不同的。后一种方法需要创建一个临时变量,并将其用作copy-ctor的参数(即使在实践中忽略了这一点)。@Ethouris,我已经更新了答案来解释这一点。在
    =
    的右侧,语言规则说有一个临时
    Atreturn
    对象。即使该临时文件被删除,关于重载和转换的规则也必须像临时文件是创建的一样。@JonathanWakely关于您上次的编辑:将其设置为
    Atreturn(t&&t):functdesr(std::forward(t))
    ?@AntonSavin,生成的代码没有区别,我最近被说服,当直接使用对象时(例如,将其复制到此处的成员变量中),应首选按值复制,而当仅转发到其他函数时,应首选转发引用。这就是
    std::function
    的工作方式。