consteval函数类型转换失败,外部转换正常的技术问询
问题:consteval函数替代宏时函数指针转换失败
我正在编写Python调用C++类的轻量包装层,Python调用C函数有三种签名:
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, PyObject *); typedef PyObject *(*PyNoArgsFunction)(PyObject *);
PyMethodDef结构体统一用PyCFunction存储函数,通过flags成员在运行时区分实际调用类型。
我写了一个函数模板用于包装类成员函数:
template<auto Fn> PyObject* member_wrapper(PyObject* obj, PyObject* args, PyObject* kwargs)
Fn是待包装的成员函数指针,用宏PY_WRAP可以正常转换:
#define PY_WRAP(fn) (PyCFunction)::py::member_wrapper<fn> // 编译正常 PyCFunction func = PY_WRAP(&MyClass::SomeFunc);
但改用consteval函数替代宏时出现编译错误:
template<typename T> consteval PyCFunction make_wrapper(T fn) { return (PyCFunction)::py::member_wrapper<fn>; } // 报错:error C2440: Cannot convert "PyObject *(__cdecl *)(PyObject *,PyObject *,PyObject *)" to "PyCFunction" PyCFunction func = make_wrapper(&MyClass::SomeFunc);
原因分析
模板实参的编译期要求不满足:宏是预处理阶段的文本替换,直接将
&MyClass::SomeFunc作为模板实参传入member_wrapper,编译器能直接实例化出对应的函数指针。而consteval函数中,fn是函数参数,即使是常量表达式,在函数内部也无法直接作为模板实参(复杂的成员函数指针类型会触发编译器处理差异),导致member_wrapper<fn>的实例化不符合预期。常量求值上下文的严格检查:
PyCFunction(双参数)和PyCFunctionWithKeywords(三参数)是不同签名的函数指针,跨签名强制转换属于C++标准中的未定义行为。普通编译上下文里编译器通常允许这种扩展转换,但consteval的常量求值上下文对未定义行为的检查更严格,MSVC直接拒绝了该转换。
解决方案
将成员函数指针作为模板参数传入make_wrapper,而非函数参数,既满足模板实参的编译期要求,又让转换在普通编译上下文完成:
template<auto Fn> consteval PyCFunction make_wrapper() { return (PyCFunction)::py::member_wrapper<Fn>; } // 调用方式 PyCFunction func = make_wrapper<&MyClass::SomeFunc>();
内容的提问来源于stack exchange,提问作者tkausl
相关产品推荐
相关产品推荐

