Reputation: 2652
I am having a problem getting the following live demo code to compile under visual C++ (2015). The code works fine in GCC as demonstrated here. Could someone please help me resolve this issue. I'm quite new to boost spirit qi parsing and with all the template magic in the background its quite difficult to spot the problem. I got the initial inspiration for CSV parsing from here in stack overflow.
The compiler errors reported under visual C++ (via the live online compiler) are as follows:
Error(s):
source_file.cpp(103): error C2146: syntax error: missing ';' before identifier 'context_type'
source_file.cpp(140): note: see reference to class template instantiation 'CsvGrammar<It>::final' being compiled
source_file.cpp(147): note: see reference to class template instantiation 'CsvGrammar<It>' being compiled
source_file.cpp(103): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
source_file.cpp(146): error C2079: 'CsvGrammar<std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>>::convert' uses undefined struct 'CsvGrammar<std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>>::final'
source_file.cpp(158): note: see reference to class template instantiation 'CsvGrammar<std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>>' being compiled
The errors under visual C++2015 in my desktop are shown here:
1>------ Build started: Project: ConsoleApplication1, Configuration: Debug x64 ------
1> Source.cpp
1>\\geihome1\home\jcoffey\visual studio 2015\projects\consoleapplication1\consoleapplication1\source.cpp(103): error C2146: syntax error: missing ';' before identifier 'context_type'
1> \\geihome1\home\jcoffey\visual studio 2015\projects\consoleapplication1\consoleapplication1\source.cpp(140): note: see reference to class template instantiation 'CsvGrammar<It>::final' being compiled
1> \\geihome1\home\jcoffey\visual studio 2015\projects\consoleapplication1\consoleapplication1\source.cpp(147): note: see reference to class template instantiation 'CsvGrammar<It>' being compiled
1>\\geihome1\home\jcoffey\visual studio 2015\projects\consoleapplication1\consoleapplication1\source.cpp(103): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>\\geihome1\home\jcoffey\visual studio 2015\projects\consoleapplication1\consoleapplication1\source.cpp(146): error C2079: 'CsvGrammar<std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>>::convert' uses undefined struct 'CsvGrammar<std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>>::final'
1> \\geihome1\home\jcoffey\visual studio 2015\projects\consoleapplication1\consoleapplication1\source.cpp(158): note: see reference to class template instantiation 'CsvGrammar<std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>>' being compiled
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Here is the code in question (also copied to the live demo sites indicated above)
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <iostream>
#include <boost/fusion/include/at_c.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <vector>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
enum LineItems {
SERVICENAME,
POLYNOMIAL,
MODULE,
DLMUW,
WSU,
TCP,
UDP,
INAIR,
CLIENTS,
// RXPORTDCTRL,
// TXPORTDCTRL,
// RXPORTWCTRL,
// TXPORTWCTRL,
// RXPORTD1,
// TXPORTD1,
// RXPORTD2,
// TXPORTD2,
// RXPORTD3,
// TXPORTD3,
// RXPORTD4,
// TXPORTD4,
// RXPORTW1,
// TXPORTW1,
// RXPORTW2,
// TXPORTW2
};
struct CsvLine {
std::string ServiceName;
std::string Polynomial;
std::string Module;
int DLMUW;
int WSU;
int TCP;
int UDP;
int InAir;
int Clients;
// std::string RxPortDCtrl;
// std::string TxPortDCtrl;
// std::string RxPortWCtrl;
// std::string TxPortWCtrl;
// int RxPortD1;
// int TxPortD1;
// int RxPortD2;
// int TxPortD2;
// int RxPortD3;
// int TxPortD3;
// int RxPortD4;
// int TxPortD4;
// int RxPortW1;
// int TxPortW1;
// int RxPortW2;
// int TxPortW2;
};
using Column = std::string;
using Columns = std::vector<Column>;
using CsvFile = std::vector<CsvLine>;
template<typename It>
struct CsvGrammar: qi::grammar<It, CsvFile(), qi::locals<std::vector<LineItems>>, qi::blank_type> {
CsvGrammar() : CsvGrammar::base_type(start) {
using namespace qi;
static const char colsep = ',';
item.add("ServiceName", SERVICENAME)("Polynomial", POLYNOMIAL)("Module", MODULE)("DLMUW", DLMUW)("WSU", WSU)("TCP", TCP)("UDP", UDP)("InAir", INAIR)("Clients", CLIENTS);
start = qi::omit[ header[_a=_1] ] >> eol >> line(_a) % eol;
// Module was unused
header = (item | omit[column] >> attr(MODULE)) % colsep;
line = (column % colsep) [convert];
column = quoted | *~char_(",\n");
quoted = '"' >> *("\"\"" | ~char_("\"\n")) >> '"';
BOOST_SPIRIT_DEBUG_NODES((header)(column)(quoted));
}
private:
qi::rule<It, std::vector<LineItems>(), qi::blank_type> header;
qi::rule<It, CsvFile(), qi::locals<std::vector<LineItems>>, qi::blank_type> start;
qi::rule<It, CsvLine(std::vector<LineItems> const&), qi::blank_type> line;
qi::rule<It, Column(), qi::blank_type> column;
qi::rule<It, std::string()> quoted;
qi::rule<It, qi::blank_type> empty;
qi::symbols<char, LineItems> item;
struct final {
using Ctx = typename decltype(line)::context_type;
void operator()(Columns const& columns, Ctx &ctx, bool &pass) const {
auto& csvLine = boost::fusion::at_c<0>(ctx.attributes);
auto& positions = boost::fusion::at_c<1>(ctx.attributes);
int i =0;
for (LineItems position : positions) {
switch (position) {
case SERVICENAME:
csvLine.ServiceName = columns[i];
break;
case POLYNOMIAL:
csvLine.Polynomial = columns[i];
break;
case MODULE:
csvLine.Module = columns[i];
break;
case DLMUW:
csvLine.DLMUW = atoi(columns[i].c_str());
break;
case WSU:
csvLine.WSU = atoi(columns[i].c_str());
break;
case TCP:
csvLine.TCP = atoi(columns[i].c_str());
break;
case UDP:
csvLine.UDP = atoi(columns[i].c_str());
break;
case INAIR:
csvLine.InAir = atoi(columns[i].c_str());
break;
case CLIENTS:
csvLine.Clients = atoi(columns[i].c_str());
break;
default:
break;
}
i++;
}
pass = true; // returning false fails the `line` rule
}
} convert;
};
int main() {
const std::string s =
"ServiceName,Polynomial,Module,DLMUW,WSU,TCP,UDP,InAir,Clients\n"
"ALBF,0x82608EDB,nic1,1,0,1,1,1,6\n"
"OmsMIS,0x04C11DB7,cmc,1,0,1,1,1,5\n"
"FMS1,0x82F63B78,proc3,1,0,1,1,1,4\n"
"FMS2,0x82F63B78,proc5,1,0,1,1,1,3";
auto f(begin(s)), l(end(s));
CsvGrammar<std::string::const_iterator> p;
CsvFile parsed;
bool ok = qi::phrase_parse(f, l, p, qi::blank, parsed);
if (ok) {
for (CsvLine line : parsed) {
std::cout
<< '[' << line.ServiceName << ']'
<< '[' << line.Polynomial << ']'
<< '[' << line.Module << ']'
<< '[' << line.DLMUW << ']'
<< '[' << line.WSU << ']'
<< '[' << line.TCP << ']'
<< '[' << line.UDP << ']'
<< '[' << line.InAir << ']'
<< '[' << line.Clients << ']';
std::cout << std::endl;
}
} else {
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining unparsed: '" << std::string(f, l) << "'\n";
}
Upvotes: 1
Views: 150
Reputation: 52385
I'm pretty sure that's a bug in MSVC. The compiler is choking on the decltype
for some reason (since it is a syntax error, most likely they have not implemented it yet). Here is a workaround:
using workaround = decltype(line);
using Ctx = typename workaround::context_type;
This seems like the related bug report. It's closed as deferred
... :(
Upvotes: 4