繁体   English   中英

Function 指针,它接受有和没有 noexcept

[英]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 指针:

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

?

我试着做这样的事情:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM