Naw*_*waz 16 c++ lambda c++11 std-function
以下代码无法编译:
#include <functional>
struct X
{
std::function<X()> _gen;
};
int main()
{
X x;
x._gen = [] { return X(); }; //this line is causing problem!
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么分配x._gen导致问题.无论GCC和铛是给类似的错误消息.有人可以解释一下吗?
In file included from main.cpp:1:0:
/usr/include/c++/4.8/functional: In instantiation of ‘std::function<_Res(_ArgTypes ...)>::_Requires<std::function<_Res(_ArgTypes ...)>::_CheckResult<std::function<_Res(_ArgTypes ...)>::_Invoke<_Functor>, _Res>, std::function<_Res(_ArgTypes ...)>&> std::function<_Res(_ArgTypes ...)>::operator=(_Functor&&) [with _Functor = main()::__lambda0; _Res = X; _ArgTypes = {}; std::function<_Res(_ArgTypes ...)>::_Requires<std::function<_Res(_ArgTypes ...)>::_CheckResult<std::function<_Res(_ArgTypes ...)>::_Invoke<_Functor>, _Res>, std::function<_Res(_ArgTypes ...)>&> = std::function<X()>&]’:
main.cpp:11:12: required from here
/usr/include/c++/4.8/functional:2333:4: error: no matching function for call to ‘std::function<X()>::function(main()::__lambda0)’
function(std::forward<_Functor>(__f)).swap(*this);
^
/usr/include/c++/4.8/functional:2333:4: note: candidates are:
/usr/include/c++/4.8/functional:2255:2: note: template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor)
function(_Functor);
^
/usr/include/c++/4.8/functional:2255:2: note: template argument deduction/substitution failed:
/usr/include/c++/4.8/functional:2230:7: note: std::function<_Res(_ArgTypes ...)>::function(std::function<_Res(_ArgTypes ...)>&&) [with _Res = X; _ArgTypes = {}]
function(function&& __x) : _Function_base()
^
/usr/include/c++/4.8/functional:2230:7: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘std::function<X()>&&’
/usr/include/c++/4.8/functional:2433:5: note: std::function<_Res(_ArgTypes ...)>::function(const std::function<_Res(_ArgTypes ...)>&) [with _Res = X; _ArgTypes = {}]
function<_Res(_ArgTypes...)>::
^
/usr/include/c++/4.8/functional:2433:5: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘const std::function<X()>&’
/usr/include/c++/4.8/functional:2210:7: note: std::function<_Res(_ArgTypes ...)>::function(std::nullptr_t) [with _Res = X; _ArgTypes = {}; std::nullptr_t = std::nullptr_t]
function(nullptr_t) noexcept
^
/usr/include/c++/4.8/functional:2210:7: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘std::nullptr_t’
/usr/include/c++/4.8/functional:2203:7: note: std::function<_Res(_ArgTypes ...)>::function() [with _Res = X; _ArgTypes = {}]
function() noexcept
^
/usr/include/c++/4.8/functional:2203:7: note: candidate expects 0 arguments, 1 provided
Run Code Online (Sandbox Code Playgroud)
同样,Clang抛出这个:
main.cpp:11:12: error: no viable overloaded '='
x._gen = [] { return X(); };
~~~~~~ ^ ~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2270:7: note: candidate function not viable: no known conversion from '<lambda at main.cpp:11:14>' to 'const std::function<X ()>' for 1st argument
operator=(const function& __x)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2288:7: note: candidate function not viable: no known conversion from '<lambda at main.cpp:11:14>' to 'std::function<X ()>' for 1st argument
operator=(function&& __x)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2302:7: note: candidate function not viable: no known conversion from '<lambda at main.cpp:11:14>' to 'nullptr_t' for 1st argument
operator=(nullptr_t)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2192:39: note: candidate template ignored: disabled by 'enable_if' [with _Functor = <lambda at main.cpp:11:14>]
using _Requires = typename enable_if<_Cond::value, _Tp>::type;
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2340:2: note: candidate template ignored: could not match 'reference_wrapper<type-parameter-0-0>' against '<lambda at main.cpp:11:14>'
operator=(reference_wrapper<_Functor> __f) noexcept
^
Run Code Online (Sandbox Code Playgroud)
小智 8
这是PR60594,已在GCC 4.8.3中得到修复.对该bug的评论指出了它的有效性:尽管标准要求标准库模板的模板参数是完整类型(有一些例外),但X()即使X不是,也是完整类型.
有几个成员std::function<X()>隐含地要求X是一个完整的类型.你正在使用的模板构造函数就是其中之一:它要求你的lambda的返回类型可以隐式转换为X,但是是否X可以转换为自身取决于是否X是一个完整的类型:如果它是不完整的,编译器不能统治它是不可复制的不可移动类型的可能性.
该要求如下:
20.9.11.2.1 function construct/copy/destroy [func.wrap.func.con]
8 备注:除非
fCallable(20.9.11.2)用于参数类型ArgTypes...和返回类型,否则这些构造函数不应参与重载决策R.20.9.11.2类模板函数[func.wrap.func]
2一个可调用对象
f类型的F是可赎回为参数类型ArgTypes和返回类型R如果表达式,视为未计算的操作数(第5章),是公形成(20.9.2).INVOKE(f, declval<ArgTypes>()..., R)20.9.2要求[func.require]
2定义为隐式转换为.
INVOKE(f, t1, t2, ..., tN, R)INVOKE(f, t1, t2, ..., tN)R
其他几个成员std::function也需要X是一个完整的类型.
你只是在类型X已经完成之后才使用那个构造函数,所以没有问题:在那一点上,X肯定可以隐式转换为X.
问题是在标准不支持执行此类检查的上下文中std::function执行依赖于X完整类型的检查,并且这没有考虑在已经完成X实例化之后将成为完整类型的可能性std::function<X()>.
这可能是一个gcc bug,但也许不是.它不是直接在=,而是在转换构造函数中std::function(operator=调用它).
这是一个病态的例子:
#include <iostream>
#include <functional>
struct X
{
std::function<X()> _gen;
};
X func() {return {};};
int main()
{
std::function<X()> foo1( &func ); // compiles
X unused = X{}; // copy ctor invoked
std::function<X()> foo2( &func ); // does not compile!
}
Run Code Online (Sandbox Code Playgroud)
请注意,第一个foo1工作正常,直到我导致某些代码调用副本ctor,第二个生成错误.即便auto unused =[]{ return X{}; };就够了.(func直接构造,永不复制).
复制ctor的使用/"创建"似乎导致了问题.
#include <iostream>
#include <functional>
struct X
{
std::function<X()> _gen;
X( X const& ) = default;
X() = default;
};
X func() {return {};};
int main()
{
std::function<X()> foo1( &func ); // does not compile
}
Run Code Online (Sandbox Code Playgroud)
复制构造函数最终调用复制ctor _gen,可能之前X是完整类型.
如果我们明确地延迟实例化X::X(X const&)直到X是一个完整的类型:
#include <functional>
struct X
{
std::function<X()> _gen;
X( X const& );
X() {}
};
X::X( X const& o ):_gen(o._gen){} // or =default *here*
X func() {return {};};
int main()
{
std::function<X()> foo1( &func ); // compiles!
[]{ return X{}; }; // or X unused = X{};
std::function<X()> foo2( &func ); // compiles!
}
Run Code Online (Sandbox Code Playgroud)
问题消失了.
我怀疑X在Xwhen 的主体中创建的隐式复制构造函数X是一个不完整的类型隐式调用std::function<X()>的复制构造函数,它在一个X不完整的上下文中,这打破了其复制构造函数被调用的前提条件(至少在实践中)如何在gcc中实现 - 按标准实现?我不确定.)
通过明确地制作复制文件,X我避免这种情况,一切正常.
因此,作为解决问题的方法,X::X(X const&)在外面声明和实现X,魔术错误消失了.
| 归档时间: |
|
| 查看次数: |
2064 次 |
| 最近记录: |