问题描述
- C++11中变参数模版和变参数宏混用的问题
- 定义了一个模版,模版参数定义为可变,想通过宏来实例化,可变的模板参数也通过宏来传递,初步的实现及测试代码如下:
#include <QCoreApplication>#include <iostream>// 模板类:template<typename T typename... _Args>struct RuntimeClass{ T* (*m_pfnFunction)(_Args&&... __args);};// 实例化声明宏:#define DECL_RUNTIMECLASS(T className ...) static RuntimeClass<T __VA_ARGS__> class_##className;// 实例化实现宏#define IMPL_RUNTIMECLASS(T className pfnFunc ...) RuntimeClass<T __VA_ARGS__> className::class_##className={pfnFunc};class TestClass{public: int TestFunc(void); DECL_RUNTIMECLASS(int TestClass)};int TestClass::TestFunc(void){ return 3;}IMPL_RUNTIMECLASS(int TestClass TestClass::TestFunc)int main(int argc char *argv[]){ QCoreApplication a(argc argv); TestClass b; std::cout<<b.class_TestClass.m_pfnFunction()<<std::endl; return a.exec();}
编译器为MinGW-w64 v4.9.2,编译时报告的错误有:
..testconsolemain.cpp:12:38: error: template argument 2 is invalid static RuntimeClass<T __VA_ARGS__> class_##className; ^..testconsolemain.cpp:23:5: note: in expansion of macro 'DECL_RUNTIMECLASS' DECL_RUNTIMECLASS(int TestClass) ^..testconsolemain.cpp:16:28: error: template argument 2 is invalid RuntimeClass<T __VA_ARGS__> className::class_##className ^..testconsolemain.cpp:31:1: note: in expansion of macro 'IMPL_RUNTIMECLASS' IMPL_RUNTIMECLASS(int TestClass TestClass::TestFunc) ^..testconsolemain.cpp:17:1: error: invalid type in declaration before '=' token ={pfnFunc}; ^..testconsolemain.cpp:31:1: note: in expansion of macro 'IMPL_RUNTIMECLASS' IMPL_RUNTIMECLASS(int TestClass TestClass::TestFunc) ^..testconsolemain.cpp:17:10: error: cannot convert 'int (TestClass::*)()' to 'int' in initialization ={pfnFunc}; ^..testconsolemain.cpp:31:1: note: in expansion of macro 'IMPL_RUNTIMECLASS' IMPL_RUNTIMECLASS(int TestClass TestClass::TestFunc) ^..testconsolemain.cpp: In function 'int main(int char**)':..testconsolemain.cpp:38:34: error: request for member 'm_pfnFunction' in 'TestClass::class_TestClass' which is of non-class type 'int' std::cout<<b.class_TestClass.m_pfnFunction()<<std::endl;
初步看起来似乎是变参数宏的__VA_ARGS__用在模板参数上时出的问题,我又尝试了将两个宏的调用代码分别改为:
DECL_RUNTIMECLASS(int TestClass void)
和
IMPL_RUNTIMECLASS(int TestClass TestClass::TestFunc void)
然后编译器报错:
..testconsolemain.cpp: In instantiation of 'struct RuntimeClass<int void>':..testconsolemain.cpp:31:1: required from here..testconsolemain.cpp:7:41: error: forming reference to void T* (*m_pfnFunction)(_Args&&... __args); ^..testconsolemain.cpp:17:10: error: too many initializers for 'RuntimeClass<int void>' ={pfnFunc}; ^..testconsolemain.cpp:31:1: note: in expansion of macro 'IMPL_RUNTIMECLASS' IMPL_RUNTIMECLASS(int TestClass TestClass::TestFunc void) ^..testconsolemain.cpp: In function 'int main(int char**)':..testconsolemain.cpp:38:34: error: 'struct RuntimeClass<int void>' has no member named 'm_pfnFunction' std::cout<<b.class_TestClass.m_pfnFunction()<<std::endl;
目前没什么头绪了,请高手帮忙解决,谢谢!
解决方案
没人回答吗?
我自己回答吧:
代码中有三处错误:
1. 类TestClass
的成员函数TestFunc
不是静态成员,不能为struct::m_pfnFunction
赋值;
2. struct RuntimeClass::m_pfnFunction
的类型是返回值为T*
的函数的指针,也与赋值对象TestClass::TestFunc
的类型不匹配;
3. 宏DECL_RUNTIMECLASS
和IMPL_RUNTIMECLASS
中的变长宏参数__VA_ARGS__
在使用的位置前有逗号时,必须加上前缀##
来匹配空的变长宏参数,否则宏展开后将因为存在多余的逗号而导致编译报错。
感谢forum.qt.io用户Chris Kawa先生的热心帮助,在他的耐心指导下我终于解决了!
时间: 2024-09-20 19:18:23