函数指针接受带有或不带有 noexcept 的函数指针

Eva*_*ran 4 c++ templates function-pointers noexcept c++17

我有一些实用程序代码,多年来一直使用它们来安全地调用 ctype 系列函数,它看起来像这样:

template<int (&F)(int)>
int safe_ctype(unsigned char c) {
    return F(c);
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用:

int r = safe_ctype<std::isspace>(ch);
Run Code Online (Sandbox Code Playgroud)

这个想法是,它可以处理将输入转换为无符号值的需要int,以防止未定义的行为。不过,这个函数的具体细节有些无关紧要。这是我的问题:

现在在 C++17 及更高版本中,noexcept是类型系统的一部分,这是一个编译错误!因为所有 ctype 函数现在都是noexcept.


编辑:上面的句子是不正确的。ctype 函数族不是 noexcept. 然而,我在 gcc < 11.2 中遇到编译器错误。https://godbolt.org/z/cTq94q5xE

该代码在所有 3 个主要编译器的最新版本中按预期工作(尽管由于这些函数不可寻址而在技术上不允许)。


我当然可以将我的函数更改为如下所示:

template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
    return F(c);
}
Run Code Online (Sandbox Code Playgroud)

但现在编译为 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
Run Code Online (Sandbox Code Playgroud)

对于如此简单的任务来说,这变得越来越复杂。那么有没有办法让函数指针:

  1. 适用于 C++11 - C++20
  2. 在 C++17+ 中同时接受 noexcept 和非 noexcept

我尝试做这样的事情:

template<class F>
int safe_ctype(unsigned char c) noexcept {
    return F(c);
}
Run Code Online (Sandbox Code Playgroud)

希望它能接受“任何东西”,但遗憾的是,没有。

想法?

eer*_*ika 7

现在在 C++17 及更高版本中,noexcept 是类型系统的一部分,这是一个编译错误!因为所有 ctype 函数现在都是 noexcept。

这不是编译错误。指向 noexcept 函数的指针可以隐式转换为指向潜在抛出函数的指针,因此接受指向潜在抛出函数的指针的模板可以与潜在抛出函数和 noexcept 函数一起使用。唯一需要注意的是,无例外信息会丢失,并且可能不会用于优化目的。

因此,原解满足第 1 点和第 2 点。


注释中指出的另一个问题是std::isspace您打算使用的标准库函数()未指定为“可寻址”。因此,由于形成了指向它们的指针,因此程序的行为是未指定的(可能是格式错误的)。

要包装此类可调用函数,您可以使用 lambda 而不是函数指针。但这使得模板本身变得过时,因为您可以直接更改 lambda 的参数类型:

auto safe_isspace = [](unsigned char c){ return std::isspace(c); };
int r = safe_isspace(ch);
Run Code Online (Sandbox Code Playgroud)

尽管我们不再需要将其传递到模板中,但可以使用普通函数来实现相同的效果:

int // or bool?
safe_isspace(unsigned char c) noexcept // ...
Run Code Online (Sandbox Code Playgroud)

由于这涉及多个函数的一些相同的样板,因此这是元编程的一个很好的候选者。