C++ 构造函数中的通用引用导致失败,can';t将可调用函子赋给std::function
在下面的完整测试用例中,如果我使用第一个按值获取函子并将其移动到位的向量,那么代码将按照预期编译和工作 但是,如果我使用通用引用ctor,它将无法编译(我在下面包含了叮当声错误消息) 我如何解决这个问题,或者我做错了什么C++ 构造函数中的通用引用导致失败,can';t将可调用函子赋给std::function,c++,templates,c++11,universal-reference,C++,Templates,C++11,Universal Reference,在下面的完整测试用例中,如果我使用第一个按值获取函子并将其移动到位的向量,那么代码将按照预期编译和工作 但是,如果我使用通用引用ctor,它将无法编译(我在下面包含了叮当声错误消息) 我如何解决这个问题,或者我做错了什么 #include <functional> #include <utility> #include <exception> template<typename F> struct py_catch { F func;
#include <functional>
#include <utility>
#include <exception>
template<typename F>
struct py_catch {
F func;
/*
//Works
py_catch(F f)
: func ( std::move(f) )
{ } */
//Doesn't
template<typename F2>
py_catch(F2&& f)
: func ( std::forward<F2>(f) )
{ }
py_catch(py_catch&&)=default;
py_catch(const py_catch&)=default;
py_catch& operator=(const py_catch&)=default;
py_catch& operator=(py_catch&&)=default;
template<typename... Args>
auto operator()(Args&&... args)
-> decltype(func(std::forward<Args>(args)...)) {
try {
return func(std::forward<Args>(args)...);
}
catch(const std::exception&) {
throw;
}
}
};
template<typename F>
py_catch<typename std::remove_reference<F>::type> make_py_catch(F&& f) {
return py_catch<typename std::remove_reference<F>::type>(std::forward<F>(f));
}
int main() {
std::function<void()> s;
s = make_py_catch([]{});
}
#包括
#包括
#包括
模板
结构py_catch{
F func;
/*
//工作
py_捕捉(F)
:func(标准::移动(f))
{ } */
//没有
模板
py_捕捉(F2和f)
:func(标准::前进(f))
{ }
py_catch(py_catch&&)=默认值;
py_catch(const py_catch&)=默认值;
py_catch&运算符=(const py_catch&)=默认值;
py_catch&operator=(py_catch&&)=默认值;
模板
自动运算符()(Args&&…Args)
->decltype(func(std::forward(args)…){
试一试{
返回函数(std::forward(args)…);
}
捕获(const std::exception&){
投掷;
}
}
};
模板
py_catch make_py_catch(F&F){
返回py_捕捉(标准::前进(f));
}
int main(){
std::函数s;
s=使捕获([]{});
}
编译错误:
testcase2.cpp:16:7: error: no matching constructor for initialization of '<lambda at testcase2.cpp:43:23>'
: func ( std::forward<F2>(f) )
^ ~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1764:10: note: in instantiation of function template specialization 'py_catch<<lambda at testcase2.cpp:43:23> >::py_catch<py_catch<<lambda at testcase2.cpp:43:23> > &>' requested here
new _Functor(*__source._M_access<_Functor*>());
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1799:8: note: in instantiation of member function 'std::_Function_base::_Base_manager<py_catch<<lambda at testcase2.cpp:43:23> > >::_M_clone' requested here
_M_clone(__dest, __source, _Local_storage());
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:2298:33: note: in instantiation of member function 'std::_Function_base::_Base_manager<py_catch<<lambda at testcase2.cpp:43:23> > >::_M_manager' requested here
_M_manager = &_My_handler::_M_manager;
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:2173:4: note: in instantiation of function template specialization 'std::function<void ()>::function<py_catch<<lambda at testcase2.cpp:43:23> > >' requested here
function(std::forward<_Functor>(__f)).swap(*this);
^
testcase2.cpp:43:7: note: in instantiation of function template specialization 'std::function<void ()>::operator=<py_catch<<lambda at testcase2.cpp:43:23> > >' requested here
s = make_py_catch([]{});
^
testcase2.cpp:43:23: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'py_catch<<lambda at testcase2.cpp:43:23> >' to 'const <lambda at testcase2.cpp:43:23>' for 1st argument
s = make_py_catch([]{});
^
testcase2.cpp:43:23: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'py_catch<<lambda at testcase2.cpp:43:23> >' to '<lambda at testcase2.cpp:43:23>' for 1st argument
s = make_py_catch([]{});
^
testcase2.cpp:43:23: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
1 error generated.
testcase2.cpp:16:7:错误:没有用于“”初始化的匹配构造函数
:func(标准::前进(f))
^ ~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../../../../include/c++/4.7.2/functional:1764:10:注意:在函数模板专门化的实例化中,此处请求“py_catch::py_catch”
新的_函子(*__source._M_access());
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../../../../../include/c++/4.7.2/functional:1799:8:注意:在成员函数的实例化中,此处请求“std::_function_base::_base_manager::_M_clone”
_M_clone(u dest,u source,_Local_storage());
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../../../../../include/c++/4.7.2/functional:2298:33:注意:在成员函数的实例化中,此处请求“std::_function_base::_base_manager::_M_manager”
_M_经理=&_我的处理程序::_M_经理;
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../../../../../include/c++/4.7.2/functional:2173:4:注意:在函数模板专门化的实例化中,此处请求“std::function::function”
函数(std::forward(_f)).swap(*this);
^
testcase2.cpp:43:7:注意:在函数模板专门化的实例化中,此处请求了“std::function::operator=”
s=使捕获([]{});
^
testcase2.cpp:43:23:注意:候选构造函数(隐式副本构造函数)不可行:没有已知的第一个参数从“py_catch”到“const”的转换
s=使捕获([]{});
^
testcase2.cpp:43:23:注意:候选构造函数(隐式移动构造函数)不可行:没有已知的第一个参数从“py_catch”到“”的转换
s=使捕获([]{});
^
testcase2.cpp:43:23:注意:候选构造函数(隐式默认构造函数)不可行:需要0个参数,但提供了1个
生成1个错误。
我认为问题在于转换构造函数模板模板py_catch(F2&&)
太贪婪了。触发错误的另一种方法是:
int main() {
auto x( make_py_catch([]{}) );
auto y(x);
}
此复制构造使用某种类型的左值py\u catch
。复制构造函数需要一个py\u catch常量&
,而贪婪模板提供了一个重载,其类型为py\u catch&
。[over.ics.rank]/3中的一条特殊规则现在表示,优先使用引用不太合格类型的重载。因此,调用的不是复制构造函数,而是构造函数模板,它尝试使用整个py_catch
对象(而不是其func
成员)初始化数据成员(lambda)
一个简单但可能不是最优的解决方案是为非常量左值py_-catch(py_-catch&)=default提供另一个拷贝向量代码>。但是,当您使用继承或用户定义转换时,构造函数模板仍然是首选
另一个解决方案是在构造函数模板上使用一些SFINAE;例如,检查是否相同
,是否基本
或类似的内容(请记住删除F2
中可能的引用)<代码>是可转换的
也可以工作,但我怀疑它会递归地尝试使用构造函数模板进行检查。我认为问题在于转换构造函数模板模板py_catch(F2&&)
太贪婪了。触发错误的另一种方法是:
int main() {
auto x( make_py_catch([]{}) );
auto y(x);
}
此复制构造使用某种类型的左值py\u catch
。复制构造函数需要一个py\u catch常量&
,而贪婪模板提供了一个重载,其类型为py\u catch&
。[over.ics.rank]/3中的一条特殊规则现在表示,优先使用引用不太合格类型的重载。因此,调用的不是复制构造函数,而是构造函数模板,它尝试使用整个py_catch
对象(而不是其func
成员)初始化数据成员(lambda)
一个简单但可能不是最优的解决方案是为非常量左值py_-catch(py_-catch&)=default提供另一个拷贝向量代码>。但是,当您使用继承或用户定义转换时,构造函数模板仍然是首选
另一个解决方案是在构造函数模板上使用一些SFINAE;例如,检查是否相同
,是否基本
或类似的内容(请记住删除F2
中可能的引用)<代码>是可转换的
也可以工作,但我怀疑它可能会递归地尝试使用构造函数模板来执行I