From 3e8fe63473b047bf3d48c734750334244e9981a8 Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Sun, 11 Aug 2019 19:57:34 +0200 Subject: Reduce boilerplate code by using C++11 variadic templates and perfect forwarding --- src/index.h | 75 +++++-------------------- src/outputlist.cpp | 159 ----------------------------------------------------- src/outputlist.h | 79 ++++++-------------------- 3 files changed, 32 insertions(+), 281 deletions(-) diff --git a/src/index.h b/src/index.h index c6baba5..f571375 100644 --- a/src/index.h +++ b/src/index.h @@ -18,6 +18,7 @@ #ifndef INDEX_H #define INDEX_H +#include #include #include @@ -55,61 +56,17 @@ class IndexList : public IndexIntf private: QList m_intfs; - // --- foreach implementations for various number of arguments - - void foreach(void (IndexIntf::*methodPtr)()) - { - QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(); - } - - template - void foreach(void (IndexIntf::*methodPtr)(A1),A1 a1) - { - QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1); - } - - template - void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3),A1 a1,A2 a2,A3 a3) - { - QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3); - } - - template - void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4),A1 a1,A2 a2,A3 a3,A4 a4) - { - QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4); - } - - template - void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4,A5),A1 a1,A2 a2,A3 a3,A4 a4,A5 a5) - { - QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4,a5); - } - - template - void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4,A5,A6),A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6) - { - QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4,a5,a6); - } - - template - void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4,A5,A6,A7,A8),A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8) - { - QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4,a5,a6,a7,a8); - } - - template - void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4,A5,A6,A7,A8,A9),A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9) + // For each index format we forward the method call. + // We use C++11 variadic templates and perfect forwarding to implement foreach() generically, + // and split the types of the methods from the arguments passed to allow implicit conversions. + template + void foreach(void (IndexIntf::*methodPtr)(Ts...),As&&... args) { QListIterator li(m_intfs); - for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4,a5,a6,a7,a8,a9); + for (li.toFirst();li.current();++li) + { + (li.current()->*methodPtr)(std::forward(args)...); + } } public: @@ -137,17 +94,15 @@ class IndexList : public IndexIntf void addContentsItem(bool isDir, const char *name, const char *ref, const char *file, const char *anchor,bool separateIndex=FALSE,bool addToNavIndex=FALSE, const Definition *def=0) - { if (m_enabled) foreach - (&IndexIntf::addContentsItem,isDir,name,ref,file,anchor,separateIndex,addToNavIndex,def); } + { if (m_enabled) foreach(&IndexIntf::addContentsItem,isDir,name,ref,file,anchor,separateIndex,addToNavIndex,def); } void addIndexItem(const Definition *context,const MemberDef *md,const char *sectionAnchor=0,const char *title=0) - { if (m_enabled) foreach - (&IndexIntf::addIndexItem,context,md,sectionAnchor,title); } + { if (m_enabled) foreach(&IndexIntf::addIndexItem,context,md,sectionAnchor,title); } void addIndexFile(const char *name) - { if (m_enabled) foreach(&IndexIntf::addIndexFile,name); } + { if (m_enabled) foreach(&IndexIntf::addIndexFile,name); } void addImageFile(const char *name) - { if (m_enabled) foreach(&IndexIntf::addImageFile,name); } + { if (m_enabled) foreach(&IndexIntf::addImageFile,name); } void addStyleSheetFile(const char *name) - { if (m_enabled) foreach(&IndexIntf::addStyleSheetFile,name); } + { if (m_enabled) foreach(&IndexIntf::addStyleSheetFile,name); } private: bool m_enabled; diff --git a/src/outputlist.cpp b/src/outputlist.cpp index daf3270..c47c1c9 100644 --- a/src/outputlist.cpp +++ b/src/outputlist.cpp @@ -196,163 +196,4 @@ void OutputList::parseText(const QCString &textStr) delete root; } - -//-------------------------------------------------------------------------- -// Create some overloaded definitions of the forall function. -// Using template functions here would have made it a little less -// portable (I guess). - -// zero arguments -void OutputList::forall(void (OutputGenerator::*func)()) -{ - QListIterator it(m_outputs); - OutputGenerator *og; - for (it.toFirst();(og=it.current());++it) - { - if (og->isEnabled()) (og->*func)(); - } -} - -// one argument -#define FORALL1(a1,p1) \ -void OutputList::forall(void (OutputGenerator::*func)(a1),a1) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1); \ - } \ -} - -// two arguments -#define FORALL2(a1,a2,p1,p2) \ -void OutputList::forall(void (OutputGenerator::*func)(a1,a2),a1,a2) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1,p2); \ - } \ -} - -// three arguments -#define FORALL3(a1,a2,a3,p1,p2,p3) \ -void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3),a1,a2,a3) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1,p2,p3); \ - } \ -} - -// four arguments -#define FORALL4(a1,a2,a3,a4,p1,p2,p3,p4) \ -void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4),a1,a2,a3,a4) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1,p2,p3,p4); \ - } \ -} - -// five arguments -#define FORALL5(a1,a2,a3,a4,a5,p1,p2,p3,p4,p5) \ -void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4,a5),a1,a2,a3,a4,a5) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1,p2,p3,p4,p5); \ - } \ -} - -// six arguments -#define FORALL6(a1,a2,a3,a4,a5,a6,p1,p2,p3,p4,p5,p6) \ -void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4,a5,a6),a1,a2,a3,a4,a5,a6) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1,p2,p3,p4,p5,p6); \ - } \ -} - -// seven arguments -#define FORALL7(a1,a2,a3,a4,a5,a6,a7,p1,p2,p3,p4,p5,p6,p7) \ -void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4,a5,a6,a7),a1,a2,a3,a4,a5,a6,a7) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1,p2,p3,p4,p5,p6,p7); \ - } \ -} - - -// eight arguments -#define FORALL8(a1,a2,a3,a4,a5,a6,a7,a8,p1,p2,p3,p4,p5,p6,p7,p8) \ -void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4,a5,a6,a7,a8),a1,a2,a3,a4,a5,a6,a7,a8) \ -{ \ - QListIterator it(m_outputs); \ - OutputGenerator *og; \ - for (it.toFirst();(og=it.current());++it) \ - { \ - if (og->isEnabled()) (og->*func)(p1,p2,p3,p4,p5,p6,p7,p8); \ - } \ -} - -// now instantiate only the ones we need. - -FORALL1(const char *a1,a1) -FORALL1(char a1,a1) -FORALL1(int a1,a1) -FORALL1(DotClassGraph &a1,a1) -FORALL1(DotInclDepGraph &a1,a1) -FORALL1(DotCallGraph &a1,a1) -FORALL1(DotDirDeps &a1,a1) -FORALL1(DotGfxHierarchyTable &a1,a1) -FORALL1(DotGroupCollaboration &a1,a1) -FORALL1(SectionTypes a1,a1) -#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE) -FORALL1(bool a1,a1) -FORALL2(bool a1,int a2,a1,a2) -FORALL2(bool a1,bool a2,a1,a2) -FORALL2(const char *a1,bool a2,a1,a2) -FORALL4(const char *a1,const char *a2,const char *a3,bool a4,a1,a2,a3,a4) -#endif -FORALL2(int a1,bool a2,a1,a2) -FORALL2(bool a1,const char *a2,a1,a2) -FORALL2(ParamListTypes a1,const char *a2,a1,a2) -FORALL1(IndexSections a1,a1) -FORALL2(const char *a1,const char *a2,a1,a2) -FORALL2(const char *a1,int a2,a1,a2) -FORALL2(const char *a1,SectionInfo::SectionType a2,a1,a2) -FORALL3(bool a1,HighlightedItem a2,const char *a3,a1,a2,a3) -FORALL3(bool a1,bool a2,bool a3,a1,a2,a3) -FORALL3(const ClassDiagram &a1,const char *a2,const char *a3,a1,a2,a3) -FORALL3(const char *a1,const char *a2,const char *a3,a1,a2,a3) -FORALL3(const char *a1,const char *a2,bool a3,a1,a2,a3) -FORALL3(const char *a1,int a2,const char *a3,a1,a2,a3) -FORALL3(const char *a1,const char *a2,SectionInfo::SectionType a3,a1,a2,a3) -FORALL3(uchar a1,uchar a2,uchar a3,a1,a2,a3) -FORALL3(const Definition *a1,const char *a2,bool a3,a1,a2,a3) -FORALL4(SectionTypes a1,const char *a2,const char *a3,const char *a4,a1,a2,a3,a4) -FORALL4(const char *a1,const char *a2,const char *a3,const char *a4,a1,a2,a3,a4) -FORALL4(const char *a1,const char *a2,const char *a3,int a4,a1,a2,a3,a4) -FORALL5(const char *a1,const char *a2,const char *a3,const char *a4,const char *a5,a1,a2,a3,a4,a5) -FORALL5(const char *a1,const char *a2,const char *a3,const char *a4,bool a5,a1,a2,a3,a4,a5) -FORALL6(const char *a1,const char *a2,const char *a3,const char *a4,const char *a5,const char *a6,a1,a2,a3,a4,a5,a6) -FORALL6(const char *a1,const DocLinkInfo &a2,const char *a3,const char *a4,const SourceLinkInfo &a5,const SourceLinkInfo &a6,a1,a2,a3,a4,a5,a6) -FORALL7(const char *a1,const char *a2,const char *a3,const char *a4,int a5,int a6,bool a7,a1,a2,a3,a4,a5,a6,a7) - - //-------------------------------------------------------------------------- diff --git a/src/outputlist.h b/src/outputlist.h index 2a83020..cfd3773 100644 --- a/src/outputlist.h +++ b/src/outputlist.h @@ -18,6 +18,7 @@ #ifndef OUTPUTLIST_H #define OUTPUTLIST_H +#include #include #include "index.h" // for IndexSections #include "outputgen.h" @@ -109,8 +110,6 @@ class OutputList : public OutputDocInterface { forall(&OutputGenerator::startTitle); } void endTitle() { forall(&OutputGenerator::endTitle); } - //void newParagraph() - //{ forall(&OutputGenerator::newParagraph); } void startParagraph(const char *classDef=0) { forall(&OutputGenerator::startParagraph,classDef); } void endParagraph() @@ -176,8 +175,6 @@ class OutputList : public OutputDocInterface { forall(&OutputGenerator::startGroupHeader,extraLevels); } void endGroupHeader(int extraLevels=0) { forall(&OutputGenerator::endGroupHeader,extraLevels); } - //void writeListItem() - //{ forall(&OutputGenerator::writeListItem); } void startItemListItem() { forall(&OutputGenerator::startItemListItem); } void endItemListItem() @@ -492,70 +489,28 @@ class OutputList : public OutputDocInterface { forall(&OutputGenerator::addWord,word,hiPriority); } void startPlainFile(const char *name) - { - QListIterator it(m_outputs); - OutputGenerator *og; - for (;(og=it.current());++it) - { - if (og->isEnabled()) (og->startPlainFile)(name); - } - } + { forall(&OutputGenerator::startPlainFile,name); } void endPlainFile() - { - QListIterator it(m_outputs); - OutputGenerator *og; - for (;(og=it.current());++it) - { - if (og->isEnabled()) (og->endPlainFile)(); - } - } + { forall(&OutputGenerator::endPlainFile); } private: void debug(); void clear(); - void forall(void (OutputGenerator::*func)()); - FORALLPROTO1(const char *); - FORALLPROTO1(char); - FORALLPROTO1(IndexSections); - FORALLPROTO1(int); - FORALLPROTO1(DotClassGraph &); - FORALLPROTO1(DotInclDepGraph &); - FORALLPROTO1(DotCallGraph &); - FORALLPROTO1(DotGroupCollaboration &); - FORALLPROTO1(DotDirDeps &); - FORALLPROTO1(DotGfxHierarchyTable &); - FORALLPROTO1(SectionTypes); -#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE) - FORALLPROTO1(bool); - FORALLPROTO2(bool,int); - FORALLPROTO2(bool,bool); - FORALLPROTO2(const char *,bool); - FORALLPROTO4(const char *,const char *,const char *,int); -#endif - FORALLPROTO2(int,bool); - FORALLPROTO2(bool,const char *); - FORALLPROTO2(ParamListTypes,const char *); - FORALLPROTO2(const char *,const char *); - FORALLPROTO2(const char *,int); - FORALLPROTO2(const char *,SectionInfo::SectionType); - FORALLPROTO3(bool,HighlightedItem,const char *); - FORALLPROTO3(bool,bool,bool); - FORALLPROTO3(const char *,const char *,bool); - FORALLPROTO3(const char *,int,const char *); - FORALLPROTO3(const char *,const char *,SectionInfo::SectionType); - FORALLPROTO3(uchar,uchar,uchar); - FORALLPROTO3(const char *,const char *,const char *); - FORALLPROTO3(const ClassDiagram &,const char *,const char *); - FORALLPROTO3(const Definition*,const char *,bool); - FORALLPROTO4(SectionTypes,const char *,const char *,const char *); - FORALLPROTO4(const char *,const char *,const char *,const char *); - FORALLPROTO4(const char *,const char *,const char *,bool); - FORALLPROTO5(const char *,const char *,const char *,const char *,const char *); - FORALLPROTO5(const char *,const char *,const char *,const char *,bool); - FORALLPROTO6(const char *,const char *,const char *,const char *,const char *,const char *); - FORALLPROTO6(const char *,const DocLinkInfo &,const char *,const char *,const SourceLinkInfo &,const SourceLinkInfo &); - FORALLPROTO7(const char *,const char *,const char *,const char *,int,int,bool); + // For each output format that is enabled (OutputGenerator::isEnabled()) we forward + // the method call. + // We use C++11 variadic templates and perfect forwarding to implement forall() generically, + // and split the types of the methods from the arguments passed to allow implicit conversions. + template + void forall(void (T::*methodPtr)(Ts...),As&&... args) + { + QListIterator li(m_outputs); + OutputGenerator *og; + for (li.toFirst();(og=li.current());++li) + { + if (og->isEnabled()) (og->*methodPtr)(std::forward(args)...); + } + } OutputList(const OutputList &ol); QList m_outputs; -- cgit v0.12