特定场景下如何从C++静态成员函数调用非静态成员函数
问题解决:静态成员函数调用非静态成员函数的编译错误
错误原因
静态成员函数func属于类本身而非类的实例,没有隐含的this指针;而非静态成员函数xupv必须依赖类的实例对象才能调用,直接在静态函数中调用会触发编译错误。同时,若将func改为非静态成员函数,由于非静态成员函数的签名隐含this指针,无法直接作为普通函数指针传递给QCDNUM::evolfg。
解决方案
通过给Local_类添加静态成员变量保存实例指针,让静态函数func能通过该指针调用非静态成员函数xupv,具体步骤如下:
- 在
Local_类中声明静态指针成员,用于存储当前实例的地址; - 在创建
local对象后,将其地址赋值给该静态指针; - 在静态函数
func中,通过静态指针调用xupv。
修改后的代码示例
#include <iostream> #include <iomanip> #include <cmath> #include <fstream> #include "QCDNUM/QCDNUM.h" #include <boost/math/quadrature/trapezoidal.hpp> #include <vector> using boost::math::quadrature::trapezoidal; using namespace std::complex_literals; using std::cout; using std::end; double M = 932.17; double B = 1.0 / 73.0; double m_u = 162; double m_d = 81; double V = 4.0 / 3.0 * 3.14159 * pow(0.0056, 3); double R = 0.0056; auto f(double m, double n){ class Local_ { public: int a; int b; static Local_* instance; // 静态指针,保存当前实例地址 auto xupv( double x ) { auto z = [&](double E){ auto a_1 = a*b*E; return a_1; }; auto e = trapezoidal(z, x * M / 2.0, M / 2.0); auto d = pow(x, 2) * pow(M, 2) / 2.0; return e * d; }; static auto func(int *ipdf, double *x) { int i = *ipdf; double xb = *x; double f = 0; if (i == 1) f = instance->xupv(xb); // 通过静态指针调用非静态成员函数 // 其他分支保持不变 return f; }; } local; Local_::instance = &local; // 将当前实例地址赋值给静态指针 // ----------------------------------------------------------- int ityp = 1, iord = 3, nfin = 0; // unpol, NLO, VFNS double as0 = 0.364, r20 = 2.0; // input alphas double xmin[] = {1.e-4, 1.e-3, 1.e-2, 1.e-1}; // x-grid int iwt[] = {1, 1, 1, 1}, ng = 4, nxin = 100, iosp = 3; // x-grid int nqin = 60; // mu2-grid double qq[] = {1e0, 15}, wt[] = {1e0, 1e0}; // mu2-grid double q2c = 3, q2b = 25, q0 = 1; // thresholds, mu20 double x = 1, q = 15, qmz2 = 8315.25, pdf[13]; double def[] = // input flavour composition // tb bb cb sb ub db g d u s c b t {0., 0., 0., 0., 0., -1., 0., 1., 0., 0., 0., 0., 0., // 1=dval 0., 0., 0., 0., -1., 0., 0., 0., 1., 0., 0., 0., 0., // 2=uval 0., 0., 0., -1., 0., 0., 0., 0., 0., 1., 0., 0., 0., // 3=sval 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., // 4=dbar 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., // 5=ubar 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., // 6=sbar 0., 0., -1., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., // 7=cval 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., // 8=cbar 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., // 9=zero 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., // 10=zero 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., // 11=zero 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}; // 12=zero int nx, nq, id1, id2, nw, nfout, ierr; double eps; int lun = 6; std::string outfile = " "; QCDNUM::qcinit(lun, outfile); // initialize QCDNUM::gxmake(xmin, iwt, ng, nxin, nx, iosp); // x-grid QCDNUM::gqmake(qq, wt, 2, nqin, nq); // mu2-grid QCDNUM::wtfile(1, "../weights/unpolarised.wgt"); // calculate weights QCDNUM::setord(iord); // LO, NLO, NNLO QCDNUM::setalf(as0, r20); // input alphas int iqc = QCDNUM::iqfrmq(q2c); // charm threshold int iqb = QCDNUM::iqfrmq(q2b); // bottom threshold QCDNUM::setcbt(nfin, iqc, iqb, 999); // thresholds in the VFNS int iq0 = QCDNUM::iqfrmq(q0); // start scale QCDNUM::evolfg(11, Local_::func, def, iq0, eps); // 传递静态成员函数指针 QCDNUM::allfxq(1, x, q, pdf, 0, 1); // interpolate all pdf's auto res = (pow(2.0 / 3.0, 2)) * (pdf[8] + pdf[4]) + (pow(1.0 / 3, 2)) * (pdf[7] + pdf[5]) + (pow(1 / 3.0, 2)) * (pdf[9] + pdf[3]); cout << res << endl; } // 初始化局部类的静态成员变量 decltype(f(0,0))::Local_* decltype(f(0,0))::Local_::instance = nullptr; int main() { f(5, 6); return 0; }
注意事项
- 由于
Local_是函数f内部的局部类,其静态成员变量的初始化需要在函数外部进行,这里使用decltype推导类型完成初始化; - 该方案适用于单线程场景,若涉及多线程,需要添加同步机制避免实例指针被并发修改;
- 若
QCDNUM::evolfg支持传递用户自定义上下文参数(如额外的void*参数),可以优先选择该方式传递实例指针,避免使用静态变量带来的全局状态问题。
内容的提问来源于stack exchange,提问作者atharva kotibhaskar
相关产品推荐
相关产品推荐

