C++11中变参数模版和变参数宏混用的问题

问题描述

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_RUNTIMECLASSIMPL_RUNTIMECLASS中的变长宏参数__VA_ARGS__在使用的位置前有逗号时,必须加上前缀##来匹配空的变长宏参数,否则宏展开后将因为存在多余的逗号而导致编译报错。

感谢forum.qt.io用户Chris Kawa先生的热心帮助,在他的耐心指导下我终于解决了!

时间: 2024-09-20 19:18:23

C++11中变参数模版和变参数宏混用的问题的相关文章

基于.Net中的协变与逆变的深入分析_实用技巧

关于协变和逆变要从面向对象继承说起.继承关系是指子类和父类之间的关系:子类从父类继承所以子类的实例也就是父类的实例.比如说Animal是父类,Dog是从Animal继承的子类:如果一个对象的类型是Dog,那么他必然是Animal.协变逆变正是利用继承关系 对不同参数类型或返回值类型 的委托或者泛型接口之间做转变.我承认这句话很绕,如果你也觉得绕不妨往下看看.如果一个方法要接受Dog参数,那么另一个接受Animal参数的方法肯定也可以接受这个方法的参数,这是Animal向Dog方向的转变是逆变.如

char-dos中的bug还是字体变大后显示的差别?

问题描述 dos中的bug还是字体变大后显示的差别? 自己写的java代码,输出的应该是一个char的空字符,dos中输出的也是一个char类型的空字符,但是如果将dos中属性下的字体调成10_*20,空的字符竟然显示成了a,但是其他字体还是显示的是char类型的空字符,难道是dos中的bug?还是编码情况的问题_. 解决方案 输出到文件,或者复制粘贴到记事本再观察.感觉是你程序的问题,这应该是一个不是空格的字符.

sql-频繁查询一张不会变(很少变)的表,有什么办法提高效率,表中数据较多,大约千万条以上

问题描述 频繁查询一张不会变(很少变)的表,有什么办法提高效率,表中数据较多,大约千万条以上 如题,对于频繁查询一张不会变(很少变)的表,有什么办法提高效率,即使变了,也不需要即时数据,就像缓存一样定期更新一下都行,表中数据较多,大约千万条级别,求思路,对SQL只了解皮毛 解决方案 看你怎么查询,是统计还是取得某个条件的数据,还是根据id找某个数据. 可以采用的方式,索引,创建冗余的临时表和临时字段,存储过程 解决方案二: 另外,sql server 2014/2016数据库,支持内存表,只要你

ios开发-如何改变一个视图控制器中除一个控件变灰

问题描述 如何改变一个视图控制器中除一个控件变灰 就像图片一样,当选择器触发时,其余控件色变成灰色怎么实现?求大神开发-如何改变一个视图控制器中除一个控件变灰-ios 添加子视图控制器">

Bootstrap中文本框的宽度变窄并且加入一副验证码图片的实现方法_javascript技巧

今天项目经理刚交给一个活儿,要我实现这样一个功能:要实现的是验证码文本框变窄一点,然后右边加入一副验证码图片,并且在响应式布局的情况下在移动端访问的时候验证码图片能保持和验证码文本框在同一行,这个怎么做?难为了半天,后来找到了实现思路,下面小编把我的想法及实现过程分享给大家,有问题欢迎提出,共同学习进步! 实现思路: 实现效果图 自己往里面加入bootstrap的栅格布局代码,控制在不同分辨率下面的排布情况. 这样实现唯一的前提条件就是你的验证码图片高度需要和input框的高度一样(input框

C++11中貌似有理的右值

C++11中貌似有理的右值 C++11非常重要的一个概念是引入了右值right value(rvalue)概念,这篇文章不是长篇大论rvalue的文章,而是在我阅读c++头文件type_traits时看到一些代码的由感而发的. right value顾名思义是右值的意思,估计你能体会到这是"即将消失"的意思,如果你还不明白,可以看这个例子: Object f() { Object o; return o; } int main() { Object obj = f(); } 你可以想象

struts 2中如何通过action手动获取参数

struts2中action手动获取Session,jsp页面参数 1. ActionContext 在Struts2开发中,除了将请求参数自动设置到Action的字段中,我们往往也需要在Action里直接获取请求(Request)或会话(Session)的一些信息, 甚至需要直接对JavaServlet Http的请求(HttpServletRequest),响应(HttpServletResponse)操作. 我们需要在Action中取得request请求参数"username"的

在Python中使用HTML模版的教程

  这篇文章主要介绍了在Python中使用HTML模版的教程,HTML模版也是Python的各大框架下的一个基本功能,需要的朋友可以参考下 Web框架把我们从WSGI中拯救出来了.现在,我们只需要不断地编写函数,带上URL,就可以继续Web App的开发了. 但是,Web App不仅仅是处理逻辑,展示给用户的页面也非常重要.在函数中返回一个包含HTML的字符串,简单的页面还可以,但是,想想新浪首页的6000多行的HTML,你确信能在Python的字符串中正确地写出来么?反正我是做不到. 俗话说得

还可以这么玩:盘点iOS 11中Siri的12项新功能

本文讲的是还可以这么玩:盘点iOS 11中Siri的12项新功能,iOS 11的首次亮相带来了一些变化,其中包括增强现实游戏和更好的iMessage体验,但或许操作系统在任何方面的改变都不如Siri大. Siri有了更多的新性能,通过分享社交账号QR码得到更生动的形象,以及它可以演奏DJ. 以下是对iOS 11中Siri的所有操作方式的总结: 1.跨设备同步 通过iOS 11系统,Siri可以总结并适应你的习惯,并在你所有的苹果设备上同步这些偏好. 比如在你的联系人列表里有四个人叫Brianna