C++ 为什么分配给std::function<;X()>;不';当它是类X的成员时,是否编译?
以下代码未编译:C++ 为什么分配给std::function<;X()>;不';当它是类X的成员时,是否编译?,c++,c++11,lambda,std-function,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! } 同样,这: main.cpp:11:12:错误:没有可行的重载'=' x、 _gen=[]{return x();}; ~~~~~~ ^ ~~~
#include <functional>
struct X
{
std::function<X()> _gen;
};
int main()
{
X x;
x._gen = [] { return X(); }; //this line is causing problem!
}
同样,这:
main.cpp:11:12:错误:没有可行的重载'='
x、 _gen=[]{return x();};
~~~~~~ ^ ~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../../../../include/c++/4.8/functional:2270:7:注意:候选函数不可行:第一个参数没有从“”到“const std::function”的已知转换
运算符=(常量函数&x)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../../../../include/c++/4.8/functional:2288:7:注意:候选函数不可行:第一个参数没有从“”到“std::function”的已知转换
运算符=(函数&&&ux)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../../../../include/c++/4.8/functional:2302:7:注意:候选函数不可行:第一个参数没有从“”到“nullptr_t”的已知转换
运算符=(nullptr\u t)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../../../../include/c++/4.8/functional:2192:39:注意:忽略候选模板:由“如果启用”禁用[使用_Functor=]
使用_Requires=typename enable_if::type;
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../../../../include/c++/4.8/functional:2340:2:注意:已忽略候选模板:无法与“”匹配“引用\u包装器”
运算符=(引用包装器)无异常
^
这可能是一个gcc错误,但可能不是。它不是直接在=
中,而是在std::function
的转换构造函数中(由操作符=
调用)
这是一个病理学上的例子:
#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!
}
该复制构造函数最终调用\u 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!
}
#包括
结构X
{
标准::功能_gen;
X(X常数&);
X(){}
};
X::X(X常量&o):\u gen(o.\u gen){}//or=default*此处*
X func(){return{};};
int main()
{
std::函数foo1(&func);//编译!
[]返回X{};};//或X未使用=X{};
std::函数foo2(&func);//编译!
}
问题消失了
我怀疑当X
是不完整类型时,在X
的主体中创建的X
的隐式复制构造函数隐式调用了std::function
的复制构造函数,该构造函数位于X
不完整的上下文中,这打破了调用其复制构造函数的先决条件(至少在实践中,它是如何在gcc中实现的——按照标准?我不确定。)
通过显式地在X
之外创建一个拷贝,我避免了这种情况,并且一切正常
因此,作为解决问题的方法,声明并实现X::X(X const&)
在X
之外,神奇的错误消失了。这是一个错误,在GCC 4.8.3中得到了修复。对该错误的评论指出了它有效的原因:尽管标准要求标准库模板的模板参数是完整类型(除了一些例外),X()
是完整类型,即使X
不是
std::function
的多个成员确实隐式要求X
为完整类型。您使用的模板构造函数就是其中之一:它要求lambda的返回类型隐式转换为X
,但X
是否可转换为自身取决于X
是一个完整类型:如果它不完整,编译器不能排除它是不可压缩不可移动类型的可能性
这项要求来自:
20.9.11.2.1函数构造/复制/销毁[func.wrap.func.con]
8备注:除非参数类型ArgTypes…
和返回类型R
可调用f
(20.9.11.2),否则这些构造函数不得参与重载解析
20.9.11.2类模板函数[func.wrap.func]
2如果表达式调用(f,declval()…,R)
被视为未赋值的操作数(第5条),则类型为f
的可调用对象f
可调用参数类型ArgTypes
,返回类型为R
(第20.9.2条)
20.9.2要求[功能要求]
2将调用(f,t1,t2,…,tN,R)
定义为调用(f,t1,t2,…,tN)
隐式转换为R
std::function
的其他几个成员也要求X
为完整类型
但是,只有在类型X
已经完成之后才使用该构造函数,因此没有问题:在这一点上,X
当然可以隐式转换为X
问题在于,std::function
执行的检查依赖于X
是一个完整的类型,在标准不支持执行此类检查的情况下,这并没有考虑到std::function
实例化后,X
将成为一个完整类型的可能性VisualStudio 2012接受了这个代码。@ Duffic:如果它是编译器错误,那么很有意思的是Visual C++这次是正确的。我的CLAN接受它。我想问题是:可以<代码> STD::函数< /C> >用不完整的类型声明。@ ZCH不,它不是明确允许的。但是我不是S。如果X()
是一个不完整的类型,@zch:我找不到任何理由不能用不完整的类型声明它:它不存储类类型的数据。而且,X()
就我的理由而言不是一个不完整的类型。g++4.8.1在排除lambda(即第二个lambda)时也不会编译它
#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!
}
#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
}
#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!
}