我有这样一个实用程序类:
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
。这些转换都是“用户定义的转换序列”,这意味着它们称为构造函数,而不是诸如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/