1

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";
}
Community
  • 1
  • 1
johnco3
  • 2,401
  • 4
  • 35
  • 67
  • Have you already checked the comma in `CLIENTS,` ? – Marged Dec 08 '15 at 20:19
  • @Marged Yes, besides that is perfectly valid and that is not the issue – johnco3 Dec 08 '15 at 20:32
  • All it says is `LineItems` is not declared. Are you sure the code you are compiling is *exactly* the same as shown above? – Jesse Good Dec 08 '15 at 20:32
  • @JesseGood yeah, you can experiment with the live links if you wish, I think that the LineItems is somehow obfuscating some compiler template error in the "struct CsvGrammar: qi::grammar>, qi::blank_type> { " line – johnco3 Dec 08 '15 at 20:41
  • @JesseGood Sorry I posted some incorrect errors from Visual Studio - updated just now, you had a good point as the error I previously posted was from a previous build I had, my bad – johnco3 Dec 08 '15 at 20:50
  • I think it would help us all if your code and error messages here would be correct ... Is your code already a mcve (http://stackoverflow.com/help/mcve) ?. Judging from the fact that even parts are commented out I doubt this. – Marged Dec 08 '15 at 20:56
  • @Marged - all but 'minimal' in the mcve sense I expect - if you can ignore the commented out code and tell me what is wrong with the statement "using Ctx = typename decltype(line)::context_type;" in visual c++ then I would be a very happy camper. (that is where my error reports point to) – johnco3 Dec 08 '15 at 21:03

1 Answers1

4

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... :(

Jesse Good
  • 50,901
  • 14
  • 124
  • 166