One Unified Global Perspective
Communications with a Global Perspective
Home
Intro
Contact Us
Voice over IP
PBX Solutions
Services
Support
Glossary
Open Source
Blog
Forum

WebMail





2009 Apr 26 - Sun

Boost Preprocessor: Arrays

Typically, in some form of C++ best practice summaries, it is recommended to stay away from using the C++ Macro Preprocessor. For the most part, except when I needed to Microsoft MFC message maps, where use preprocessor macros, I have followed this maxim. Until now.

I came across a situation where one section of code is dependent upon the order of declarations in another section of code. With manual code preparation, and even if things are documented appropriately, it is easy to forget to update the inter-related sections of code properly.

An example is when initializing the column definitions of an MFC CListView. I'd like to construct an enumeration of column indexes and ensure those remain in-sync with any changes I may make to the CListView column defintions themselves.

I hadn't realized the power of the C++ macro preprocessor until I started reading Appendix A: An Introduction to Preprocessor Metaprogramming in the book "C++ Template Metaprogramming" by David Abrahams and Aleksey Gurtovoy.

By using the Boost Preprocessor Library, the power of the C++ Macro Preprocessor is realized.

I can now define my column structures and associated variables in a single header file. I also define various extraction macros.

#include "boost/preprocessor/tuple/elem.hpp"
#include "boost/preprocessor/array/elem.hpp"
#include "boost/preprocessor/array/size.hpp"
#include "boost/preprocessor/punctuation/comma_if.hpp"
#include "boost/preprocessor/repetition/repeat.hpp"


#define COLHDR_DELTAS_ARRAY_ELEMENT_SIZE 6
#define COLHDR_DELTAS_ARRAY \
  (15, \
    ( \
      (COLHDR_DELTAS_COL_UndSym, "UndSym", LVCFMT_LEFT,  50, std::string, m_sSymbolUnderlying), \
      (COLHDR_DELTAS_COL_Sym   , "Sym",    LVCFMT_RIGHT, 50, std::string, m_sSymbol), \
      (COLHDR_DELTAS_COL_Strk  , "Strk",   LVCFMT_RIGHT, 50, double,      m_dblStrike), \
      (COLHDR_DELTAS_COL_Expiry, "Expiry", LVCFMT_RIGHT, 50, ptime,       m_dtExpiry), \
      (COLHDR_DELTAS_COL_Bid   , "Bid",    LVCFMT_RIGHT, 50, double,      m_dblBid), \
      (COLHDR_DELTAS_COL_BidSz , "BidSz",  LVCFMT_RIGHT, 50, int,         m_nBidSize), \
      (COLHDR_DELTAS_COL_Sprd  , "Sprd",   LVCFMT_RIGHT, 50, double,      m_dblSpread), \
      (COLHDR_DELTAS_COL_Ask   , "Ask",    LVCFMT_RIGHT, 50, double,      m_dblAsk), \
      (COLHDR_DELTAS_COL_AskSz , "AskSz",  LVCFMT_RIGHT, 50, int,         m_nAskSize), \
      (COLHDR_DELTAS_COL_Pos   , "Pos",    LVCFMT_RIGHT, 50, int,         m_nPosition), \
      (COLHDR_DELTAS_COL_AvgCst, "AvgCst", LVCFMT_RIGHT, 50, double,      m_dblAverageCost), \
      (COLHDR_DELTAS_COL_Delta , "Delta",  LVCFMT_RIGHT, 50, double,      m_dblDelta), \
      (COLHDR_DELTAS_COL_Gamma , "Gamma",  LVCFMT_RIGHT, 50, double,      m_dblGamma), \
      (COLHDR_DELTAS_COL_UnRlPL, "UnRlPL", LVCFMT_RIGHT, 50, double,      m_dblUnrealizedPL), \
      (COLHDR_DELTAS_COL_RlPL  , "RlPL",   LVCFMT_RIGHT, 50, double,      m_dblRealizedPL) \
      ) \
    ) \
  /**/

#define COLHDR_DELTAS_EXTRACT_COL_DETAILS(z, n, m, text) \
  BOOST_PP_TUPLE_ELEM( \
    COLHDR_DELTAS_ARRAY_ELEMENT_SIZE, m, \
      BOOST_PP_ARRAY_ELEM( n, COLHDR_DELTAS_ARRAY ) \
    )

#define COLHDR_DELTAS_EXTRACT_ENUM_LIST(z, n, text) \
  BOOST_PP_COMMA_IF(n) \
  COLHDR_DELTAS_EXTRACT_COL_DETAILS( z, n, 0, text )

#define COLHDR_DELTAS_EMIT_InsertColumn( z, n, VAR ) \
  m_vuDeltas.InsertColumn( VAR++, \
    _T(COLHDR_DELTAS_EXTRACT_COL_DETAILS(z, n, 1, ~)), \
    COLHDR_DELTAS_EXTRACT_COL_DETAILS(z, n, 2, ~), \
    COLHDR_DELTAS_EXTRACT_COL_DETAILS(z, n, 3, ~) \
    );

#define COLHDR_DELTAS_EMIT_DefineVars( z, n, text ) \
  COLHDR_DELTAS_EXTRACT_COL_DETAILS(z, n, 4, ~) \
  COLHDR_DELTAS_EXTRACT_COL_DETAILS(z, n, 5, ~)\
  ;

Then in my class declaration, I can extract the enumerations in the correct 0-based order:

  enum enumColHdrDeltasCol {
    BOOST_PP_REPEAT( BOOST_PP_ARRAY_SIZE( COLHDR_DELTAS_ARRAY ), COLHDR_DELTAS_EXTRACT_ENUM_LIST, ~ )
  };

The repetitive code of creating the columns in the CListView is handled through repetition and extraction macros:

  int ix = 0;
  BOOST_PP_REPEAT( BOOST_PP_ARRAY_SIZE( COLHDR_DELTAS_ARRAY ), COLHDR_DELTAS_EMIT_InsertColumn, ix )
  // m_vuDeltas.InsertColumn( ix++, "UndSym", LVCFMT_LEFT, 50 );

I'll be able to further use the initial structure to create the row factory for keeping the CListView and row-structures synchronized. If I happen to change my mind on column ordering, all related code sections are automatically updated.

[/Personal/SoftwareDevelopment/CPP] permanent link



New blog site at: Raymond Burkholder - What I Do

Blog Content ©2013
Ray Burkholder
All Rights Reserved
ray@oneunified.net
(519) 838-6013
(441) 705-7292
Available for Contract Work
Resume

RSS: Click to see the XML version of this web page.

twitter
View Ray 
Burkholder's profile on LinkedIn
technorati
Add to Technorati Favorites



April
Su Mo Tu We Th Fr Sa
     
   


Main Links:
Monitoring Server
SSH Tools
QuantDeveloper Code

Special Links:
Frink

Blog Links:
Quote Database
Nanex Research
Sergey Solyanik
Marc Andreessen
Micro Persuasion
... Reasonable ...
Chris Donnan
BeyondVC
lifehacker
Trader Mike
Ticker Sense
HeadRush
TraderFeed
Stock Bandit
The Daily WTF
Guy Kawaski
J. Brant Arseneau
Steve Pavlina
Matt Cutts
Kevin Scaldeferri
Joel On Software
Quant Recruiter
Blosxom User Group
Wesner Moise
Julian Dunn
Steve Yegge
Max Dama

2009
Months
Apr




Mason HQ

Disclaimer: This site may include market analysis. All ideas, opinions, and/or forecasts, expressed or implied herein, are for informational purposes only and should not be construed as a recommendation to invest, trade, and/or speculate in the markets. Any investments, trades, and/or speculations made in light of the ideas, opinions, and/or forecasts, expressed or implied herein, are committed at your own risk, financial or otherwise.