[英]Function pointer which accepts both with and without noexcept
我有一些实用程序代码,多年来我一直在使用这些代码来安全地调用 ctype 系列函数,它看起来像这样:
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
并且是这样使用的:
int r = safe_ctype<std::isspace>(ch);
这个想法是它为您处理将输入int
转换为无符号值的需要,以防止未定义的行为。 这个 function 的细节有点无关紧要。 这是我的问题:
现在在 C++17 及更高版本中, noexcept
是类型系统的一部分,这是一个编译错误! 因为所有 ctype 函数现在都是noexcept
。
编辑:上面的句子是不正确的。 ctype 系列函数不是noexcept
。 但是,我在 gcc < 11.2 中遇到编译器错误。 https://godbolt.org/z/cTq94q5xE
该代码可以在所有 3 个主要编译器的最新版本中按预期工作(尽管由于这些函数不可寻址,技术上不允许这样做)。
我当然可以将我的 function 更改为如下所示:
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
但是现在编译为 C++11 或 C++14 时它不起作用。 所以我最终不得不做这样的事情:
#if __cplusplus >= 201703L
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
#else
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
#endif
对于这样一个简单的任务,这变得越来越复杂。 那么有没有办法制作 function 指针:
?
我试着做这样的事情:
template<class F>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
希望它会接受“任何东西”,但遗憾的是,没有 go。
想法?
现在在 C++17 及更高版本中, noexcept 是类型系统的一部分,这是一个编译错误。 因为现在所有的 ctype 函数都是 noexcept。
这不是编译错误。 指向 noexcept 函数的指针可以隐式转换为指向潜在抛出函数的指针,因此接受指向潜在抛出函数的指针的模板适用于潜在抛出函数和 noexcept 函数。 唯一需要注意的是,noexceptedness 信息会丢失,并且可能不会用于优化目的。
因此,原始解同时满足第 1 点和第 2 点。
评论中指出的另一个问题是您打算使用的标准库函数( std::isspace
)未指定为“可寻址”。 因此,由于形成了指向它们的指针,程序的行为是未指定的(可能是格式错误的)。
要包装此类可调用对象,您可以使用 lambda 而不是 function 指针。 但这会使模板本身过时,因为您可以直接更改 lambda 的参数类型:
auto safe_isspace = [](unsigned char c){ return std::isspace(c); };
int r = safe_isspace(ch);
虽然我们不再需要将其传递到模板中,但同样可以使用普通的 function 来实现:
int // or bool?
safe_isspace(unsigned char c) noexcept // ...
由于这涉及多个功能的一些相同样板,因此这是元编程的良好候选者。
因为现在所有的 ctype 函数都是 noexcept。
这是不真实的。 C++17 没有向通过 C++ c*
头文件访问的任何 C 库函数添加noexcept
。 您可以在此处看到所有 C++ function 声明不包含noexcept
。 并且不允许标准库实现将非noexcept
函数noexcept
。
其次,即使它是noexcept
,也可以将noexcept
function 指针转换为抛出的 function 指针(但不能反过来)。 所以你的代码编译。
但最重要的是,C++20 清楚地表明,除非特别说明,否则不允许为任何 C++ 标准库 function 获取 function 指针。 C++标准库中可寻址的函数很少。
所以在 C++20 中,你的代码会产生 UB。 如果您希望您的代码适用于所有语言版本,您只需要为 cctype 函数编写包装器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.