在this page上,我找到了一个很好的C ++函数指针示例(以åŠå‡½å,但是这个问题与函åæ— å…³ï¼‰ã€‚ä»¥ä¸‹æ˜¯è¯¥é¡µé¢ä¸Šçš„一些副本。
#include <iostream>
double add(double left, double right) {
return left + right;
}
double multiply(double left, double right) {
return left * right;
}
double binary_op(double left, double right, double (*f)(double, double)) {
return (*f)(left, right);
}
int main( ) {
double a = 5.0;
double b = 10.0;
std::cout << "Add: " << binary_op(a, b, add) << std::endl;
std::cout << "Multiply: " << binary_op(a, b, multiply) << std::endl;
return 0;
}
我一般地ç†è§£ä»£ç ,但是有些事情我总是感到困惑。函数binary_op()
带有一个函数指针*f
,但是当使用它时,例如在第19行binary_op(a, b, add)
上,函数符å·add
è¢«ä¼ å…¥ï¼Œè€Œä¸æ˜¯äººä»¬æƒ³çš„é‚£æ ·&add
作为指针。现在您å¯èƒ½ä¼šè¯´è¿™æ˜¯å› 为符å·add
是的指针;它是与功能add()
相对应的代ç ä½çš„地å€ã€‚很好,但是这里似乎ä»ç„¶å˜åœ¨ç±»åž‹å·®å¼‚。函数binary_op()
使用*f
,这æ„味ç€f
是指å‘æŸç‰©çš„æŒ‡é’ˆã€‚æˆ‘ä¼ å…¥add
,它本身就是代ç 的指针。 (对å—?)然åŽä¸ºf
分é…了add
的值,这使f
æˆä¸ºä»£ç 的指针,这æ„味ç€f
å°±åƒ{{1 }},这æ„味ç€add
的调用应åƒf
ä¸€æ ·ï¼Œç¡®åˆ‡åœ°è¯´åº”è¯¥å¦‚ä½•è°ƒç”¨f(left, right)
,但是在第12行,它的命å应åƒadd
ä¸€æ ·ï¼Œå¯¹æˆ‘æ¥è¯´ä¼¼ä¹Žå¾ˆå¯¹ï¼Œå› 为就åƒç¼–写(*f)(left, right)
ä¸€æ ·ï¼Œè€Œ(*add)(left, right)
ä¸æ˜¯å‡½æ•°ï¼Œå®ƒæ˜¯*add
指å‘的代ç 的第一个å—符。 (对å—?)
我知é“用以下内容替æ¢add
的原始定义也å¯ä»¥ã€‚
binary_op()
事实上,这对我æ¥è¯´æ„义更大,但是原始è¯æ³•æ²¡æœ‰æˆ‘上é¢è§£é‡Šçš„é‚£æ ·ã€‚
那么,为什么在è¯æ³•ä¸Šä½¿ç”¨double binary_op(double left, double right, double f(double, double)) {
return f(left, right);
}
而ä¸æ˜¯ä»…仅使用(*f)
是æ£ç¡®çš„?如果符å·f
本身就是一个指针,那么çŸè¯â€œå‡½æ•°æŒ‡é’ˆâ€æˆ–“函数指针â€åˆ°åº•æ˜¯ä»€ä¹ˆæ„æ€ï¼Ÿå°±ç›®å‰çš„原始代ç 而言,当我们编写func
时,double (*f)(double, double)
是什么一类?指å‘æŒ‡é’ˆçš„æŒ‡é’ˆï¼ˆå› ä¸ºf
本身就是指å‘一些代ç 的指针)?符å·(*f)
与add
是åŒä¸€ç§äº‹ç‰©ï¼Œè¿˜æ˜¯(*f)
是åŒä¸€ç§äº‹ç‰©ï¼Ÿ
现在,如果这一切的ç”案是“是的,C ++è¯æ³•å¾ˆå¥‡æ€ªï¼Œåªéœ€è®°ä½å‡½æ•°æŒ‡é’ˆè¯æ³•ï¼Œä¸è¦è´¨ç–‘它。†,那么我会很ä¸æƒ…愿地接å—它,但是我真的很想对我在这里的错有一个适当的解释。
我已ç»è¯»è¿‡this question,并且我认为我ç†è§£è¿™ä¸€ç‚¹ï¼Œä½†æ˜¯å¹¶æ²¡æœ‰å‘现它有助于解决我的困惑。我还读过this questionï¼Œå®ƒä¹Ÿæ— æµŽäºŽäº‹ï¼Œå› ä¸ºå®ƒä¸èƒ½ç›´æŽ¥è§£å†³æˆ‘的类型差异问题。我å¯ä»¥ç»§ç»é˜…读互è”网上的信æ¯ä¹‹æµ·ï¼Œä»¥æ‰¾åˆ°ç”案,但是,嘿,那是Stack Overflowçš„æ£ç¡®é€‰æ‹©å—?
ç”案 0 :(得分:3)
è¿™æ˜¯å› ä¸ºC函数指针是特殊的。
首先,表达å¼add
将衰å‡ä¸ºä¸€ä¸ªæŒ‡é’ˆã€‚å°±åƒå¯¹æ•°ç»„的引用会衰å‡ä¸ºæŒ‡é’ˆä¸€æ ·ï¼Œå¯¹å‡½æ•°çš„引用也会衰å‡ä¸ºå‡½æ•°çš„指针。
然åŽï¼Œé‚£é‡Œæœ‰å¥‡æ€ªçš„东西:
return (*f)(left, right);
 Â那么,为什么在è¯æ³•ä¸Šä½¿ç”¨
(*f)
而ä¸æ˜¯ä»…仅使用f
是æ£ç¡®çš„?
两个都有效,您å¯ä»¥è¿™æ ·é‡å†™ä»£ç :
return f(left, right);
è¿™æ˜¯å› ä¸ºå–消引用è¿ç®—符将​​返回对函数的引用,并且对函数的引用或函数指针都被视为å¯è°ƒç”¨çš„。
有趣的是,函数引用的衰å‡éžå¸¸å®¹æ˜“,以至于在调用å–消引用è¿ç®—符时它将衰å‡å›žæŒ‡é’ˆï¼Œä»Žè€Œå¯ä»¥æ ¹æ®éœ€è¦å¤šæ¬¡å–消引用函数:
return (*******f)(left, right); // ah! still works
ç”案 1 :(得分:1)
 Â就目å‰çš„原始代ç 而言,当我们写
double (*f)(double, double)
时,f
是什么一类?
f
的类型为double (*)(double, double)
,å³å®ƒæ˜¯æŒ‡å‘类型为double(double,double)
的函数的指针。
 Âå› ä¸º
(*f)
本身就是一个指针
ä¸æ˜¯ã€‚
问:通过指针间接进行æ“作(例如在*f
ä¸ï¼‰æ—¶ï¼Œæ‚¨ä¼šå¾—到什么?ç”:您会得到一个左值å‚考。例如,给定对象指针int* ptr
,表达å¼*ptr
的类型为int&
,å³å¯¹int
的左值引用。
对于函数指针也是如æ¤ï¼šå½“您通过函数指针间接访问时,您将获得指å‘所指å‘函数的左值引用。对于*f
,类型为double (&)(double, double)
,å³å¯¹ç±»åž‹ä¸ºdouble(double,double)
的函数的引用。
 Â符å·
add
是和(*f)
ä¸€æ ·çš„ä¸œè¥¿ï¼Œè¿˜æ˜¯f
是å—?
ä¸åˆæ ¼çš„id表达å¼add
与*f
çš„å«ä¹‰ç›¸åŒï¼Œå³å®ƒæ˜¯ä¸€ä¸ªå·¦å€¼ï¼š
 Âæ ‡å‡†è‰æ¡ˆ[expr.prim.id.unqual]
   Â...如果实体是函数,则表达å¼ä¸ºå·¦å€¼...
 Âä¼ å…¥äº†å‡½æ•°ç¬¦å·
add
,而ä¸æ˜¯ä¼ 入它的指针&add
。现在您å¯èƒ½ä¼šè¯´è¿™æ˜¯å› 为符å·add
是一个指针;
ä¸ã€‚é‚£ä¸æ˜¯åŽŸå› 。
add
ä¸æ˜¯æŒ‡é’ˆã€‚它是一个左值。但是函数类型的左值会éšå¼è½¬æ¢ä¸ºæŒ‡é’ˆï¼ˆè¿™ç§°ä¸ºè¡°å‡ï¼‰ï¼š
 Âæ ‡å‡†è‰æ¡ˆ[转æ¢åŠŸèƒ½]
   Âå¯ä»¥å°†å‡½æ•°ç±»åž‹T的左值转æ¢ä¸ºâ€œæŒ‡å‘T的指针â€çš„å‰å€¼ã€‚结果是指å‘该函数的指针。
å› æ¤ï¼Œä»¥ä¸‹åœ¨è¯ä¹‰ä¸Šæ˜¯ç‰æ•ˆçš„:
binary_op(a, b, add); // implicit function-to-pointer conversion
binary_op(a, b, &add); // explicit use of addressof operator
 Â那么,为什么在è¯æ³•ä¸Šä½¿ç”¨
(*f)
而ä¸æ˜¯ä»…仅使用f
呢?
事实è¯æ˜Žï¼Œè°ƒç”¨å‡½æ•°å·¦å€¼ä¸Žè°ƒç”¨å‡½æ•°æŒ‡é’ˆå…·æœ‰ç›¸åŒçš„è¯æ³•ï¼š
 Âæ ‡å‡†è‰ç¨¿[expr.call]
   Â函数调用是一个åŽç¼€è¡¨è¾¾å¼ï¼ŒåŽè·Ÿæ‹¬å·ï¼Œå…¶ä¸åŒ…å«å¯èƒ½ä¸ºç©ºçš„逗å·åˆ†éš”çš„åˆå§‹åŒ–程åºåå¥åˆ—表,这些åå¥æž„æˆäº†å‡½æ•°çš„å‚数。   åŽç¼€è¡¨è¾¾å¼åº”具有函数类型或函数指针类型。   对于éžæˆå‘˜å‡½æ•°æˆ–é™æ€æˆå‘˜å‡½æ•°çš„调用,åŽç¼€è¡¨è¾¾å¼åº”为引用函数的 lvalue (在这ç§æƒ…å†µä¸‹ï¼Œå‡½æ•°åˆ°æŒ‡é’ˆçš„æ ‡å‡†è½¬æ¢ä¸º[[ conv.func])在åŽç¼€è¡¨è¾¾å¼ä¸Šè¢«æŠ‘制),或具有函数指针类型。
这些都是相åŒçš„函数调用:
add(parameter_list); // lvalue
(*f)(parameter_list); // lvalue
(&add)(parameter_list); // pointer
f(parameter_list); // pointer
P.S。这两个声明是ç‰æ•ˆçš„:
double binary_op(double, double, double (*)(double, double))
double binary_op(double, double, double (double, double))
这是由于以下规则,它与éšå¼è¡°å‡åˆ°å‡½æ•°æŒ‡é’ˆäº’补:
 Âæ ‡å‡†è‰ç¨¿[dcl.fct]
   Â使用以下规则确定函数的类型。   æ¯ä¸ªå‚数(包括功能å‚数包)的类型由其自己的decl-specifier-seq和声明符确定。   确定æ¯ä¸ªå‚数的类型åŽï¼Œå°†â€œ T的数组â€ç±»åž‹çš„任何å‚数或函数类型T的调整为“指å‘T的指针†... >
ç”案 2 :(得分:1)
首先,当编译器确定å‚数的类型时,将指定为函数声明的函数å‚数调整为指å‘è¯¥å‡½æ•°çš„æŒ‡é’ˆã€‚å› æ¤ï¼Œä¾‹å¦‚下é¢çš„函数声明
void f( void h() );
void f( void ( *h )() );
是ç‰æ•ˆçš„,并且声明相åŒçš„一个函数。
请考虑以下演示程åº
#include <iostream>
void f( void h() );
void f( void ( *h )() );
void h() { std::cout << "Hello Ray\n"; }
void f( void h() ) { h(); }
int main()
{
f( h );
}
从c ++ 17 Standard(11.3.5函数)开始:
 Â5使用以下规则确定函数的类型。的   æ¯ä¸ªå‚数的类型(包括功能å‚数包)为   由自己的decl-specifier-seqå’Œå£°æ˜Žç¬¦ç¡®å®šã€‚åŽ Â Â ç¡®å®šæ¯ä¸ªå‚数的类型,“数组â€ç±»åž‹çš„任何å‚æ•°   T或功能类型T调整为“指å‘T的指针â€ã€‚
å¦ä¸€æ–¹é¢ï¼Œæ ¹æ®C ++ 17æ ‡å‡†
 Â9如果给定å‚数没有å‚数,则å‚数为   以接收函数å¯ä»¥èŽ·å–值的方å¼ä¼ 递   通过调用va_arg(21.11)æ¥ç¡®å®šå‚数。 [注æ„:本段   ä¸é€‚ç”¨äºŽä¼ é€’ç»™å‡½æ•°å‚数包的å‚数。   在模æ¿å®žä¾‹åŒ–期间扩展功能å‚数包   (17.6.3ï¼‰ï¼Œå› æ¤å½“   函数模æ¿ä¸“业化实际上是被调用的。 —尾注]   左值到å³å€¼ï¼ˆ7.1),数组到指针(7.2)和函数到指针(7.3)   对å‚数表达å¼æ‰§è¡Œæ ‡å‡†è½¬æ¢
那么这两个声明有什么区别
void f( void h() );
void f( void ( *h )() );
对于第一个声明,您å¯ä»¥åƒåœ¨å‡½æ•°æŒ‡é’ˆçš„typedefä¸é‚£æ ·è€ƒè™‘函数体内的å‚æ•°h
。
typedef void ( *H )();
例如
#include <iostream>
void f( void h() );
void f( void ( *h )() );
void h() { std::cout << "Hello Ray\n"; }
typedef void ( *H )();
void f( H h ) { h(); }
int main()
{
f( h );
}
æ ¹æ®C ++ 17æ ‡å‡†ï¼ˆ8.5.1.2函数调用)
 Â1函数调用是åŽç¼€è¡¨è¾¾å¼ï¼ŒåŽè·Ÿæ‹¬å·   包å«ä¸€ä¸ªå¯èƒ½ä¸ºç©ºä¸”以逗å·åˆ†éš”的列表   构æˆå‡½æ•°å‚æ•°çš„åˆå§‹åŒ–åå¥ã€‚   åŽç¼€è¡¨è¾¾å¼åº”具有函数类型或函数指针   输入。
å› æ¤ï¼Œæ‚¨ä¹Ÿå¯ä»¥å°†å‡½æ•°å®šä¹‰ä¸º
void f( void h() ) { ( *h )(); }
甚至喜欢
void f( void h() ) { ( ******h )(); }
å› ä¸ºå½“å°†è¿ç®—符*应用于函数å称时,该函数å称会éšå¼è½¬æ¢ä¸ºè¯¥å‡½æ•°çš„å称。