为什么分配到std :: function< X()>当它是类X的成员时不编译? [英] Why assignment to std::function<X()> doesn't compile when it is a member of class X?

查看:573
本文介绍了为什么分配到std :: function< X()>当它是类X的成员时不编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码不编译:

  #include< functional> 

struct X
{
std :: function< X()> _gen;
};

int main()
{
X x;
x._gen = [] {return X(); }; //这行引起问题!
}



我不明白为什么分配到 x。 _gen 是导致问题。 gcc clang 提供类似的错误讯息。有没有人可以解释一下?






编译器错误讯息



GCC的错误

 从main.cpp:1:0:
/usr/include/c++/4.8/functional:在实例化'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&&& _Res = X; _ArgTypes = {}; std :: function< _Res(_ArgTypes ...)> :: _需要< std :: function< _Res(_ArgTypes ...)> :: _ CheckResult< std :: function< _Res(_ArgTypes ...)> :: _ Invoke< _Functor>,_Res>,std :: function< _Res(_ArgTypes ...)>& = std :: function< X()&];
main.cpp:11:12:从这里需要
/usr/include/c++/4.8/functional:2333:4:错误:没有匹配的函数调用'std :: function< X()> :: function(main():: __ lambda0)'
function(std :: forward< _Functor> (*这个);
^
/usr/include/c++/4.8/functional:2333:4:注意:候选人是:
/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:模板参数扣除/替换失败:
/usr/include/c++/4.8/functional:2230: 7:note:std :: function< _Res(_ArgTypes ...)> :: function(std :: function< _Res(_ArgTypes ...)>&& _ArgTypes = {}]
函数(函数&& __x):_Function_base()
^
/usr/include/c++/4.8/functional:2230:7:注意:参数1从'main():: __ lambda0'到'std :: function< X()>&&'
/usr/include/c++/4.8/functional:2433:5: 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:注意:参数1从'main():: __ lambda0'转换为'const std :: function< X()&'
/usr/include/c++/4.8/functional:2210:7: std :: function< _Res(_ArgTypes ...)> :: function(std :: nullptr_t)[with _Res = X; _ArgTypes = {}; std :: nullptr_t = std :: nullptr_t]
函数(nullptr_t)noexcept
^
/usr/include/c++/4.8/functional:2210:7:注意:没有已知的参数转换1从'main():: __ lambda0'到'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:注意:候选人期望有0个参数,1提供

同样, Clang throws this:

  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:注意:候选函数不可行:没有从'< lambda at main.cpp:11:14>'到'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:注意:候选函数不可行:没有从'到'std :: function< X()>'用于第一个参数
operator =(function&& __x)
^
/ usr / lib / gcc / x86_64-linux-gnu / 4.8 /../../../../ include / c ++ / 4.8 / functional:2302:7:note:候选函数不可行:没有从'的已知转换。 '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:注意:候选模板被忽略:被'enable_if'禁用[with _Functor =< lambda at main.cpp:11:14>]
使用_Requires = typename enable_if< _Cond :: value,_Tp> :: type;
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2340:2:注意:候选模板已忽略:无法将'reference_wrapper< type-parameter-0-0>'与'< lambda main.cpp:11:14>'匹配
operator =(reference_wrapper< _Functor> __f)noexcept
^


解决方案

这是 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 备注:不参与重载解析,除非 f 对于参数类型 ArgTypes ... 是Callable(20.9.11.2) R



20.9.11.2类模板函数[func.wrap.func]



2 F 类型的可调用对象 f 如果表达式 <$> ,则返回 c $ c> INVOKE (f,declat< ArgTypes>()...,R),被视为未求值的操作数(第5条),形成良好(20.9.2)。



20.9.2要求[func.require] b
$ b

2定义 INVOKE (f,t1,t2, (f,t1,t2,...,tN,R)作为 INVOKE tN)隐式转换为 R


std :: function 的其他成员也需要 X 才是完整类型。



之后,只要使用该构造函数, X 已经完成,所以没有问题:at这一点, X 当然可以隐式转换为 X



问题是 std :: function 执行的检查依赖于 X 是一个完整的类型,标准不支持执行此类检查的上下文,并且这未考虑在 X 将成为完整类型的可能性> std :: function< X()> 已经完成。


The following code doesn't compile:

#include <functional>

struct X
{
    std::function<X()> _gen;
};

int main()
{
    X x;
    x._gen = [] { return X(); }; //this line is causing problem!
}

I don't understand why assignment to x._gen is causing problem. Both gcc and clang are giving similar error messages. Could anyone please explain it?


Compiler error messages

GCC's error:

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

Likewise, Clang throws this:

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
        ^

解决方案

This was PR60594, which got fixed in GCC 4.8.3. The comments on that bug point out why it is valid: although the standard requires template arguments for standard library templates to be a complete type (with some exceptions), X() is a complete type even if X is not.

There are several members of std::function<X()> that do implicitly require X to be a complete type. The template constructor you're using is one of them: it requires the return type of your lambda to be implicitly convertible to X, but whether X is convertible to itself depends on whether X is a complete type: if it's incomplete, the compiler can't rule out the possibility that it is an uncopyable unmovable type.

This requirement follows from:

20.9.11.2.1 function construct/copy/destroy [func.wrap.func.con]

8 Remarks: These constructors shall not participate in overload resolution unless f is Callable (20.9.11.2) for argument types ArgTypes... and return type R.

20.9.11.2 Class template function [func.wrap.func]

2 A callable object f of type F is Callable for argument types ArgTypes and return type R if the expression INVOKE(f, declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well formed (20.9.2).

20.9.2 Requirements [func.require]

2 Define INVOKE(f, t1, t2, ..., tN, R) as INVOKE(f, t1, t2, ..., tN) implicitly converted to R.

Several other members of std::function also require X to be a complete type.

You're only using that constructor after type X has already completed, though, so there's no problem: at that point, X certainly can be implicitly converted to X.

The problem was that std::function was performing checks that depend on X being a complete type, in a context where the standard doesn't support performing such checks, and this did not account for the possibility that X would become a complete type after the instantiation of std::function<X()> had already completed.

这篇关于为什么分配到std :: function&lt; X()&gt;当它是类X的成员时不编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆