我有这样一个实用程序类:

struct Atreturn
{
    std::function<void()> funcdestr;
    Atreturn( std::function<void()> fd ): funcdestr(fd) {}
    ~Atreturn() { funcdestr(); }
};

注意构造器上没有explicit属性。

可能的用途应该是:
  • 直接初始化构造函数调用:
    Atreturn hook ( [something]() { DestroySomething(something); } );
    
  • 复制初始化构造函数调用:
    Atreturn hook = [something]() { DestroySomething(something); };
    
  • 直接列表初始化构造函数调用:
    Atreturn hook { [something]() { DestroySomething(something); }};
    

  • 现在的问题是:就我所知,方法#1和#2在理论上是相同的,因此应该允许它们使用,但前提是在构造函数中没有explicit,而应该不允许方法#3,因为此语法会阻止转换(在如果您尝试int,那么int{2.1}至少是这样)。

    但是,gcc 4.9允许方法#1和#3,但不允许方法#2(并说conversion from '...::<lambda()>' to non-scalar 'Atreturn' type requested)。这听起来很疯狂,因为它通常仅在您具有explicit构造函数时才会发生。谁能解释,为什么?

    另外,让我更明确地说明这个问题:我需要一些不太笨拙的语法来初始化此Atreturn对象,至少不需要额外的花括号或括号。问题在于,当参数为C++ 11 lambda时,具有自动缩进功能的编辑器会出现正确重新缩进的问题。所以我需要一些可以表示为的语法:
     Atreturn BLAH BLAH BLAH [something]() { DestroySomething(something); };
    

    最佳答案



    那不是很正确。规则是不允许缩小转换。允许其他类型的转换。 int{2.1}是一种缩小的转换,因为它会修改值,从而失去精度。 int{2.0}不是缩小转换,因为该值未更改。

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

    从概念上讲,复制初始化如:

    Atreturn hook = []() {};
    

    等效于:
    Atreturn hook = Atreturn([]() {});
    

    (除了它不能调用“显式”构造函数,并且允许编译器删除拷贝)。

    这意味着,首先,lambda必须隐式转换为function<void()>,然后必须隐式转换为Atreturn。这些转换都是“用户定义的转换序列”,这意味着它们称为构造函数,而不是诸如intlong之类的内置转换,并且标准表示隐式转换序列不能包含多个用户定义的转换。

    该问题实际上与lambda无关,您可以演示完全相同的错误,如下所示:
    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<void()>的任何内容,例如
    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)) { }
      ...
    };
    

    这将允许将lambda直接转换为Atreturn,而无需先进行隐式转换为function<void()>

    关于c++ - 初始化和lambda类型的参数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28875231/

    10-11 23:15
    查看更多