When I use a big header-only library like Boost Spirit, I often want to isolate its includes into a single cpp file (parser.cpp
),
in order to reduce the needed compilation time to one file only. The goal is that when a source file (main.cpp
) needs the Spirit facilities,
it can include a header file which presents a front class with no reference to any Spirit stuff, letting this source file compile quickly.
Only one cpp file (parser.cpp
) needs to include the Spirit headers and take more time to compile.
But how to create a class which needs Spirit internally, without any reference to it into its declaration?
The only way I found is by using a pointer member to an incomplete wrapper class (QiParser
), then use new
and delete
internally
to create the real parser.
My question is: is there a better way to do this, without using new
and delete
?
Here is the kind of code I use now:
main.cpp
#include <iostream>
#include "parser.h"
int main (int, char **)
{
Parser p;
int n = 0;
p.parse("78", n);
std::cout << "The parsed number is " << n << std::endl;
return 0;
}
parser.h
#include <string>
class QiParser; //< Incomplete class declaration
class Parser {
public:
Parser();
~Parser();
bool parse(const std::string &s, int &result) const;
private:
QiParser *qi_parser; //< The only way I found to not include
// the Spirit headers in this file
};
parser.cpp
#include "parser.h"
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
// The QiParser class is only present to solve my problem;
// I would like to put this code directly into the Parser class, but without showing
// any Spirit stuff inside the parser.h header file
struct QiParser : qi::grammar<std::string::const_iterator, int()>
{
QiParser() : base_type(start)
{
start %= qi::int_;
}
qi::rule<std::string::const_iterator, int()> start;
};
// Implementation of the Parser class:
Parser::Parser()
{
qi_parser = new QiParser;
}
Parser::~Parser()
{
delete qi_parser;
}
bool Parser::parse(const std::string &s, int &result) const
{
auto iter = s.begin(), end = s.end();
return qi::parse(iter, end, *qi_parser, result);
}