c++ - 初始化和 lambda 类型参数

标签 c++ c++11 constructor lambda initialization

我有这样一个实用类:

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

备注编号 explicit构造函数中的属性。

可能的用途应该是:

  1. 直接初始化构造函数调用:

    Atreturn hook ( [something]() { DestroySomething(something); } );
    
  2. 复制初始化构造函数调用:

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

    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); };

最佳答案

while #3 should not be allowed because this syntax prevents conversions (at least it's so for int if you tried int{2.1}).

这不太对。规则是不允许缩小转换。允许其他类型的转换。 int{2.1}是缩小转换,因为它修改了值,失去了精度。 int{2.0}不是缩小转换,因为值没有改变。

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

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

Atreturn hook = []() {};

相当于:

Atreturn hook = Atreturn([]() {});

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

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

该问题实际上与 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/

相关文章:

c++ - 我们应该尽可能使用 constexpr 吗?

python - 使用现有实例初始化 super?

c++ - 默认成员值最佳实践

c++ - 在 Windows 上的个人项目中使用 Crypto++

c++ - 检查多边形是否在 C++ 中相交

c++ - 处理类和指针

c# - 如何在 C# 中的方法中调用构造函数

c++ - friend 类不能调用私有(private)构造函数

c++ - 从 friend 类继承时无法使用大括号括起来的初始值设定项列表

与不同 C++ 标准链接的 C++ std 库