C++中引用函数是否仍需取地址运算符&?标准依据及C++23变化
关于C++函数名传参是否需要加&的疑问解答
核心结论
在C++中,传递函数名时是否加&取地址运算符完全是可选的——两种写法std::thread t(foo);和std::thread t(&foo);在标准下是合法且行为等价的,加&不是语法要求,只是风格选择。
1. 函数名的隐式转换(标准规定)
根据C++标准的**[expr.prim.id.unqual]**条款:当函数名出现在需要作为表达式使用的语境中(除非是sizeof、decltype等不需要转换的运算符操作数),会自动隐式转换为指向该函数的指针。
举个简单例子:
void foo() {} // 以下两行完全等价,foo会自动转换成&foo void (*fp1)() = foo; void (*fp2)() = &foo;
cppreference提到的“函数不是对象,无法按值传递或返回”是准确的——你确实不能直接传递函数本身,但传递函数名时,编译器会自动生成对应的函数指针,实际传递的是这个指针,而非函数本体,这完全符合标准规则。
2. std::thread构造函数的处理逻辑(C++20及更早)
在C++20及之前,std::thread的模板构造函数会通过decay-copy处理传入的可调用对象。对于函数名来说,decay操作会把函数类型直接转换成对应的函数指针类型。所以不管你传foo还是&foo,经过decay-copy后得到的都是同一个函数指针,最终的线程行为没有任何区别。
3. C++23的构造函数变化不影响此场景
C++23将std::thread构造函数的处理逻辑改为使用auto std::forward(f),但这并不会破坏原有行为:
- 当你传入函数名
foo时,它作为左值会依然触发隐式转换,生成函数指针; - 传入
&foo时,本身就是函数指针,std::forward会直接传递这个指针。
两种写法在C++23中依然等价,不会出现行为差异,你完全不用担心兼容性问题。
4. 为什么有人习惯加&?
这纯粹是编码风格问题:
- 加
&可以更直观地表明这里传递的是函数指针,让代码意图更清晰,减少新手的困惑; - 某些场景下(比如传递重载函数时),加
&可以帮助编译器明确选择哪个重载版本,但对于无重载的普通函数来说,这不是必须的。
内容的提问来源于stack exchange,提问作者Superlokkus
相关产品推荐
相关产品推荐

