C++ 由函数指针初始化的std::函数的异常安全性

C++ 由函数指针初始化的std::函数的异常安全性,c++,c++17,C++,C++17,未声明std::function的构造函数noexcept: 模板函数(F); 另一方面,C++引用提到以下内容: 如果f是函数指针或std::reference_包装器,则不会抛出, 否则可能会抛出std::bad_alloc或副本引发的任何异常 存储的可调用对象的构造函数 这是否意味着可以安全地声明以下类的构造函数noexcept,因为我使用指向静态成员函数的指针初始化std::function 类工作者 { 公众: Worker()没有异常{}//可以吗? void test(){rep

未声明
std::function
的构造函数
noexcept

模板函数(F);
另一方面,C++引用提到以下内容:

如果f是函数指针或std::reference_包装器,则不会抛出, 否则可能会抛出std::bad_alloc或副本引发的任何异常 存储的可调用对象的构造函数

这是否意味着可以安全地声明以下类的构造函数
noexcept
,因为我使用指向静态成员函数的指针初始化
std::function

类工作者
{
公众:
Worker()没有异常{}//可以吗?
void test(){reporter(“test”);}
私人:
静态空虚拟(const std::string&){};
std::function reporter=&dummy;//是否不引发异常?
};
int main()
{
工人w;
w、 test();
}
如果
std::function
成员是从lambda构造的,那么声明构造函数
noexcept
将是错误的

类工作者
{
公众:
Worker()无异常{}//错误?
void test(){reporter(“test”);}
私人:
std::function reporter=[](const std::string&){};//可以抛出吗?
};
我还注意到,当构造函数声明为
noexcept
时,GCC会给出一个错误,因为它的异常规范与隐式异常规范不匹配,隐式异常规范是
noexcept(false)
,因为
std::function
构造函数未声明为noexcept

类工作者
{
公众:
Worker()noexcept=default;//这不会编译
void test(){reporter(“test”);}
私人:
静态空虚拟(const std::string&){};
std::function reporter=&dummy;
};
这是否意味着可以安全地声明以下类的构造函数
noexcept
,因为我使用指向静态成员函数的指针初始化
std::function

请注意,声明函数
noexcept
总是“安全的”。如果抛出异常,程序将终止,但这不是未定义的行为

但是是的,在您的情况下,不应该抛出任何异常,因此不应该终止程序。标准说:“如果
f
是函数指针,则不会抛出任何内容。”

如果
std::function
成员是从lambda构造的,那么声明构造函数
noexcept
将是错误的

是的,它在您想要的意义上是“错误的”(如果抛出,程序将终止),因为lambda不是函数指针。相反,在lambda前面加上一元
运算符+
,使其成为函数指针:

std::function<void (const std::string&)> reporter = +[](const std::string& ){};
std::function reporter=+[](const std::string&){};
我可能会在评论中提到这一点,特别是如果您没有评论为什么构造函数是
noexcept

我还注意到,当构造函数声明的
noexcept
为默认值时,GCC会给出一个错误


GCC和Clang的最新版本都没有给出错误,因此如果这是真的,则可能是标准中发布的缺陷报告。

我相信您的两个问题的答案都是“是”。编译器无法自动检测到构造函数不能抛出,因为
std::function
的构造函数没有声明
noexcept
,在标准的散文中它只是被描述为有时不抛出。我想有可能提供几个
std::function
构造函数的重载,使用SFINAE技术将那些可以标记为
noexcept
的构造函数与那些不能标记的构造函数分开,但不管是好是坏,该标准并不要求这样做。
noexcept
default
之间的交互作用在中已修复(追溯)。非常感谢您的参考!这似乎是其中之一,是的。