我可以使用标准库中定义的函数的地址吗? [英] Can I take the address of a function defined in standard library?

查看:115
本文介绍了我可以使用标准库中定义的函数的地址吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

#include <cctype>
#include <functional>
#include <iostream>

int main()
{
    std::invoke(std::boolalpha, std::cout); // #1

    using ctype_func = int(*)(int);
    char c = std::invoke(static_cast<ctype_func>(std::tolower), 'A'); // #2
    std::cout << c << "\n";
}

此处,对std::invoke的两个调用已标记为将来参考. 预期的输出是:

Here, the two calls to std::invoke are labeled for future reference. The expected output is:

a

C ++ 20是否保证了预期的输出?

Is the expected output guaranteed in C++20?

(注意:有两个函数称为tolower—一个在<cctype>中,另一个在<locale>中.引入了显式强制转换以选择所需的重载.)

(Note: there are two functions called tolower — one in <cctype> and the other in <locale>. The explicit cast is introduced to select the desired overload.)

推荐答案

简短答案

否.

[namespace.std] 说:

F 表示标准库函数( [global .functions] ),标准库静态成员函数或标准库函数模板的实例化. 除非 F 被指定为可寻址函数,否则C ++程序的行为(如果它明确或隐式地试图形成一个C ++程序)是不确定的(可能是不正确的).指向 F 的指针. [注意:形成此类指针的可能方法包括应用一元&运算符( [expr.unary.op] ),addressof( [specialized.addressof] )或函数到指针的标准转换( [conv.func] ). — 尾注] 此外,如果C ++程序试图形成对 F 的引用,或者试图形成指定标准的成员的指针,则它的行为是不确定的(可能是格式错误的).库非静态成员函数( [member.functions] )或一个实例化标准库成员函数模板.

Let F denote a standard library function ([global.functions]), a standard library static member function, or an instantiation of a standard library function template. Unless F is designated an addressable function, the behavior of a C++ program is unspecified (possibly ill-formed) if it explicitly or implicitly attempts to form a pointer to F. [Note: Possible means of forming such pointers include application of the unary & operator ([expr.unary.op]), addressof ([specialized.addressof]), or a function-to-pointer standard conversion ([conv.func]). — end note ] Moreover, the behavior of a C++ program is unspecified (possibly ill-formed) if it attempts to form a reference to F or if it attempts to form a pointer-to-member designating either a standard library non-static member function ([member.functions]) or an instantiation of a standard library member function template.

考虑到这一点,让我们检查对std::invoke的两次调用.

With this in mind, let's check the two calls to std::invoke.

std::invoke(std::boolalpha, std::cout);

在这里,我们正在尝试形成指向std::boolalpha的指针.幸运的是, [fmtflags.manip] 保存了这一天:

Here, we are attempting to form a pointer to std::boolalpha. Fortunately, [fmtflags.manip] saves the day:

此子节中指定的每个函数都是指定的可寻址函数( [namespace.std] ).

boolalpha是此子节中指定的功能. 因此,此行格式正确,等效于:

And boolalpha is a function specified in this subclause. Thus, this line is well-formed, and is equivalent to:

std::cout.setf(std::ios_base::boolalpha);

那为什么呢?好吧,下面的代码是必要的:

But why is that? Well, it is necessary for the following code:

std::cout << std::boolalpha;

第二通电话

std::cout << std::invoke(static_cast<ctype_func>(std::tolower), 'A') << "\n";

不幸的是, [cctype.syn] 说:

标头<cctype>的内容和含义与C标准库标头<ctype.h>相同.

The contents and meaning of the header <cctype> are the same as the C standard library header <ctype.h>.

tolower在任何地方都未明确指定可寻址功能.

Nowhere is tolower explicitly designated an addressable function.

因此,此C ++程序的行为未指定(可能格式错误),因为它试图形成指向tolower的指针,而该指针未指定为可寻址函数.

Therefore, the behavior of this C++ program is unspecified (possibly ill-formed), because it attempts to form a pointer to tolower, which is not designated an addressable function.

不能保证预期的输出. 实际上,甚至不保证代码可以编译.

The expected output is not guaranteed. In fact, the code is not even guaranteed to compile.

这也适用于成员函数. [namespace.std]并未明确提及这一点,但是从[member.functions]可以看出,如果C ++程序尝试获取已声明的成员函数的地址,则该行为是不确定的(可能是格式错误的)在C ++标准库中.根据 [member.functions]/2 :

This also applies to member functions. [namespace.std] doesn’t explicitly mention this, but it can be seen from [member.functions] that the behavior of a C++ program is unspecified (possibly ill-formed) if it attempts to take the address of a member function declared in the C++ standard library. Per [member.functions]/2:

对于C ++标准库中描述的非虚拟成员函数,实现可以声明一组不同的成员函数签名,前提是对该成员函数的任何调用都会从本文档中描述的声明集中选择一个重载.文档的行为就像选择了该重载一样. [注意:例如,一个实现可以添加具有默认值的参数,或者用具有相同行为的两个或多个成员函数将成员函数替换为具有默认参数的成员函数,或者为成员函数名称添加其他签名. — 尾注]

For a non-virtual member function described in the C++ standard library, an implementation may declare a different set of member function signatures, provided that any call to the member function that would select an overload from the set of declarations described in this document behaves as if that overload were selected. [ Note: For instance, an implementation may add parameters with default values, or replace a member function with default arguments with two or more member functions with equivalent behavior, or add additional signatures for a member function name. — end note ]

[expr.unary.op]/6 :

仅在唯一确定要引用哪个版本的重载函数的上下文中才能使用重载函数的地址(请参见[over.over]). [注意:由于上下文可能确定操作数是静态还是非静态成员函数,因此上下文也会影响表达式是函数指针"还是成员函数指针" . — 尾注]

The address of an overloaded function can be taken only in a context that uniquely determines which version of the overloaded function is referred to (see [over.over]). [ Note: Since the context might determine whether the operand is a static or non-static member function, the context can also affect whether the expression has type "pointer to function" or "pointer to member function". — end note ]

因此,如果程序的行为显式或隐式地尝试形成指向C ++库中成员函数的指针,则该行为是不确定的(可能是格式错误的).

Therefore, the behavior of a program is unspecified (possibly ill-formed) if it explicitly or implicitly attempts to form a pointer to a member function in the C++ library.

(感谢 查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆