c++ - 当 std::function<X()> 是 X 类的成员时,为什么不能编译它?

标签 c++ c++11 lambda std-function

以下代码无法编译:

#include <functional>

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

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

我不明白为什么分配给 x._gen 会导致问题。两个gccclang正在给出类似的错误消息。谁能解释一下?


编译器错误信息

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

同样,Clang throws这个:

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
        ^

最佳答案

这是 PR60594 ,在 GCC 4.8.3 中得到修复。对该错误的评论指出了它为什么有效:尽管标准要求标准库模板的模板参数是完整类型(有一些异常(exception)),X()是一个完整的类型,即使 X不是。

std::function<X()> 有几个成员确实需要X成为一个完整的类型。您正在使用的模板构造函数就是其中之一:它要求您的 lambda 的返回类型可以隐式转换为 X , 但是否 X是否可转换为自身取决于 X是完整类型:如果不完整,编译器不能排除它是不可复制不可移动类型的可能性。

此要求来自:

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.

std::function 的其他几个成员还需要X成为一个完整的类型。

你只是在类型X之后使用那个构造函数不过已经完成了,所以没有问题:此时,X当然可以隐式转换为X .

问题是 std::function正在执行依赖于 X 的检查作为一个完整类型,在标准不支持执行此类检查的情况下,这并没有考虑到 X 的可能性。 std::function<X()> 实例化后将成为完整类型已经完成了。

关于c++ - 当 std::function<X()> 是 X 类的成员时,为什么不能编译它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20129601/

相关文章:

c++ - boost mapped_file_source、对齐方式和页面大小

c++ - boost::transform_iterator 不适用于 std::bind( &Pair::first, _1 )?

c++ - 使用 move::semantic 将大量 vector 合并为一个更大的 vector

python - 使用多处理在 Python 中制作并行版本的 map 函数时出现 Pickle 错误

c++ - std::transform with lambda: 跳过一些项目

c++ - 创建指向运行时创建的函数的函数指针

c++ - 实现接口(interface)类的纯虚方法的方法也应该声明为虚方法吗?

c++ - 在类(class)结束时声明私有(private)成员有什么好处?

c++ - 如何使用 CMake 将外部库( boost )包含到 CLion C++ 项目中?

c++ - visual studio 2012 中的 initializer_list