Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ boost::spirit::qi::语法和可变模板_C++_Parsing_Variadic Templates_Boost Spirit Qi - Fatal编程技术网

C++ boost::spirit::qi::语法和可变模板

C++ boost::spirit::qi::语法和可变模板,c++,parsing,variadic-templates,boost-spirit-qi,C++,Parsing,Variadic Templates,Boost Spirit Qi,我在用可变模板定义语法时遇到了一个问题 我首先定义了一些包含在某些结构(例如纬度、经度)中的简单语法,如下所示: #include <boost/fusion/include/adapt_struct.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/variant.hpp> #include <iostream> #include <string> using n

我在用可变模板定义语法时遇到了一个问题

我首先定义了一些包含在某些结构(例如纬度、经度)中的简单语法,如下所示:

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <string>

using namespace boost::spirit;

template <class Attribute>
using command_rule =
    qi::rule<std::string::iterator, Attribute, ascii::space_type>;

template <class Attribute>
using command_grammar =
    qi::grammar<std::string::iterator, Attribute, ascii::space_type>;

struct Latitude {

  struct return_type {
    double lat_;
  };

  struct grammar : command_grammar<return_type()> {
    grammar() : grammar::base_type{latitude_} {
      latitude_ = "LAT=" >> qi::double_;
    }

  private:
    command_rule<return_type()> latitude_;
  };
};

BOOST_FUSION_ADAPT_STRUCT(Latitude::return_type, (double, lat_))

struct Longitude {

  struct return_type {
    double lon_;
  };

  struct grammar : command_grammar<return_type()> {
    grammar() : grammar::base_type{longitude_} {
      longitude_ = "LON=" >> qi::double_;
    }

  private:
    command_rule<return_type()> longitude_;
  };
};

BOOST_FUSION_ADAPT_STRUCT(Longitude::return_type, (double, lon_))
语法对象似乎不能是临时的,必须存储为类的成员。我该怎么做

编辑:
我也曾尝试将此类对象存储在
std::tuple
中,但它似乎仍然不起作用。

您正在创建的内容与qi的自动解析器的功能非常相似:

如果您专门针对您的数据类型,您可以直接使用
qi::auto

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace Commands {
    namespace qi = boost::spirit::qi;

    template <class T> using Rule = qi::rule<std::string::const_iterator, T()>;

    template <typename... T>
    auto parse(std::string const& s) {
        boost::variant<T...> v;

        auto it = s.begin();
        if (qi::parse(it, s.end(), qi::auto_, v))
            return v;
        throw std::runtime_error(std::string(__FUNCTION__) + " failed");
    }
}

struct Latitude  { double lat_; };
BOOST_FUSION_ADAPT_STRUCT(Latitude, lat_)

struct Longitude { double lon_; };
BOOST_FUSION_ADAPT_STRUCT(Longitude, lon_)

namespace boost { namespace spirit { namespace traits {
    template <> struct create_parser<Latitude> {
        using type = Commands::Rule<Latitude>;
        static type const& call() {
            static type const s_rule = qi::skip(qi::space)["LAT=" >> qi::auto_];
            return s_rule;
        };
    };

    template <> struct create_parser<Longitude> {
        using type = Commands::Rule<Longitude>;
        static type const& call() {
            static type const s_rule = qi::skip(qi::space)["LON=" >> qi::auto_];
            return s_rule;
        };
    };
} } }

struct print {
    using result_type = void;
    void operator()(Latitude const &t)  const { std::cout << "Latitude = " << t.lat_ << " deg" << std::endl; }
    void operator()(Longitude const &t) const { std::cout << "Longitude = " << t.lon_ << " deg" << std::endl; }
};

#include <sstream>

int main() {
    std::istringstream iss("LAT=4.3\n LON=5.0");
    std::string s;

    print printer;

    while (std::getline(iss, s)) try {
        auto v = Commands::parse<Latitude, Longitude>(s);
        boost::apply_visitor(printer, v);
    }
    catch (std::exception const& e) {
        std::cout << "'" << s << "': " << e.what() << "\n";
    }
}
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace Commands {
    template <typename... T>
    auto parse(std::string const& s) {
        boost::variant<T...> v;

        auto it = s.begin();
        if (boost::spirit::qi::parse(it, s.end(), boost::spirit::qi::auto_, v))
            return v;
        throw std::runtime_error(std::string(__FUNCTION__) + " failed");
    }

    struct Latitude { double lat_; };
    struct Longitude { double lon_; };

    static inline std::ostream& operator<<(std::ostream& os, Latitude const &t) { return os << "Latitude = " << t.lat_ << " deg"; }
    static inline std::ostream& operator<<(std::ostream& os, Longitude const &t) { return os << "Longitude = " << t.lon_ << " deg"; }
}

BOOST_FUSION_ADAPT_STRUCT(Commands::Latitude, lat_)
BOOST_FUSION_ADAPT_STRUCT(Commands::Longitude, lon_)

namespace boost { namespace spirit { namespace traits {
    #define MAP_PARSER(T, expr) \
    template <> struct create_parser<T> { \
        using type = decltype(qi::attr_cast<T, T>(qi::copy(expr))); \
        static type const& call() { static type const s_rule = qi::attr_cast<T, T>(qi::copy(expr)); return s_rule; }; \
    };

    #define AUTO_MAP_PARSER(T, caption) MAP_PARSER(T, qi::skip(qi::space)[qi::lit(caption) >> '=' >> qi::auto_])

    AUTO_MAP_PARSER(::Commands::Longitude, "LON")
    AUTO_MAP_PARSER(::Commands::Latitude, "LAT")
} } }

#include <sstream>

int main() {
    std::istringstream iss("LAT=4.3\n LON=5.0");
    std::string s;

    while (std::getline(iss, s)) try {
        using namespace Commands;
        std::cout << "Parsed '" << s << "' into " << parse<Latitude, Longitude>(s) << "\n";
    } catch (std::exception const& e) {
        std::cout << "'" << s << "': " << e.what() << "\n";
    }
}
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace Commands {
    namespace x3 = boost::spirit::x3;
    template <typename... T>
    auto parse(std::string const& s) {
        using V = boost::variant<T...>;
        V v;

        auto it = s.begin();
        if (x3::parse(it, s.end(), parser_for(v), v))
            return v;
        throw std::runtime_error(std::string(__FUNCTION__) + " failed");
    }

    struct Latitude { double lat_; };
    struct Longitude { double lon_; };

    auto label_for(Latitude) { return "LAT"; }
    auto label_for(Longitude) { return "LON"; }

    template <typename T, typename P>
    auto as_cmd(P p) { return x3::rule<struct _, T>{} 
            = x3::skip(x3::space)[x3::lit(label_for(T{})) >> '=' >> p]; }

    template <typename T>    auto parser_for(T)                      { return as_cmd<T>(x3::double_); }
    template <typename... T> auto parser_for(boost::variant<T...> _) { return (parser_for(T{}) | ...); }

    static inline std::ostream& operator<<(std::ostream& os, Latitude const &t) { return os << "Latitude = " << t.lat_ << " deg"; }
    static inline std::ostream& operator<<(std::ostream& os, Longitude const &t) { return os << "Longitude = " << t.lon_ << " deg"; }
}

BOOST_FUSION_ADAPT_STRUCT(Commands::Latitude, lat_)
BOOST_FUSION_ADAPT_STRUCT(Commands::Longitude, lon_)

#include <iostream>
#include <sstream>

int main() {
    std::istringstream iss("LAT=4.3\n LON=5.0");
    std::string s;

    while (std::getline(iss, s)) try {
        using namespace Commands;
        std::cout << "Parsed '" << s << "' into " << parse<Latitude, Longitude>(s) << "\n";
    } catch (std::exception const& e) {
        std::cout << "'" << s << "': " << e.what() << "\n";
    }
}
好东西 如果不使用
qi::rule
也不需要硬编码迭代器。让我们进入充满乐趣的模式,也摆脱访客:

[在线直播](

除了我给出的:

如果您有能力启用c++1z,则可以将Spirit X3与折叠表达式一起使用:

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace Commands {
    namespace qi = boost::spirit::qi;

    template <class T> using Rule = qi::rule<std::string::const_iterator, T()>;

    template <typename... T>
    auto parse(std::string const& s) {
        boost::variant<T...> v;

        auto it = s.begin();
        if (qi::parse(it, s.end(), qi::auto_, v))
            return v;
        throw std::runtime_error(std::string(__FUNCTION__) + " failed");
    }
}

struct Latitude  { double lat_; };
BOOST_FUSION_ADAPT_STRUCT(Latitude, lat_)

struct Longitude { double lon_; };
BOOST_FUSION_ADAPT_STRUCT(Longitude, lon_)

namespace boost { namespace spirit { namespace traits {
    template <> struct create_parser<Latitude> {
        using type = Commands::Rule<Latitude>;
        static type const& call() {
            static type const s_rule = qi::skip(qi::space)["LAT=" >> qi::auto_];
            return s_rule;
        };
    };

    template <> struct create_parser<Longitude> {
        using type = Commands::Rule<Longitude>;
        static type const& call() {
            static type const s_rule = qi::skip(qi::space)["LON=" >> qi::auto_];
            return s_rule;
        };
    };
} } }

struct print {
    using result_type = void;
    void operator()(Latitude const &t)  const { std::cout << "Latitude = " << t.lat_ << " deg" << std::endl; }
    void operator()(Longitude const &t) const { std::cout << "Longitude = " << t.lon_ << " deg" << std::endl; }
};

#include <sstream>

int main() {
    std::istringstream iss("LAT=4.3\n LON=5.0");
    std::string s;

    print printer;

    while (std::getline(iss, s)) try {
        auto v = Commands::parse<Latitude, Longitude>(s);
        boost::apply_visitor(printer, v);
    }
    catch (std::exception const& e) {
        std::cout << "'" << s << "': " << e.what() << "\n";
    }
}
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace Commands {
    template <typename... T>
    auto parse(std::string const& s) {
        boost::variant<T...> v;

        auto it = s.begin();
        if (boost::spirit::qi::parse(it, s.end(), boost::spirit::qi::auto_, v))
            return v;
        throw std::runtime_error(std::string(__FUNCTION__) + " failed");
    }

    struct Latitude { double lat_; };
    struct Longitude { double lon_; };

    static inline std::ostream& operator<<(std::ostream& os, Latitude const &t) { return os << "Latitude = " << t.lat_ << " deg"; }
    static inline std::ostream& operator<<(std::ostream& os, Longitude const &t) { return os << "Longitude = " << t.lon_ << " deg"; }
}

BOOST_FUSION_ADAPT_STRUCT(Commands::Latitude, lat_)
BOOST_FUSION_ADAPT_STRUCT(Commands::Longitude, lon_)

namespace boost { namespace spirit { namespace traits {
    #define MAP_PARSER(T, expr) \
    template <> struct create_parser<T> { \
        using type = decltype(qi::attr_cast<T, T>(qi::copy(expr))); \
        static type const& call() { static type const s_rule = qi::attr_cast<T, T>(qi::copy(expr)); return s_rule; }; \
    };

    #define AUTO_MAP_PARSER(T, caption) MAP_PARSER(T, qi::skip(qi::space)[qi::lit(caption) >> '=' >> qi::auto_])

    AUTO_MAP_PARSER(::Commands::Longitude, "LON")
    AUTO_MAP_PARSER(::Commands::Latitude, "LAT")
} } }

#include <sstream>

int main() {
    std::istringstream iss("LAT=4.3\n LON=5.0");
    std::string s;

    while (std::getline(iss, s)) try {
        using namespace Commands;
        std::cout << "Parsed '" << s << "' into " << parse<Latitude, Longitude>(s) << "\n";
    } catch (std::exception const& e) {
        std::cout << "'" << s << "': " << e.what() << "\n";
    }
}
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace Commands {
    namespace x3 = boost::spirit::x3;
    template <typename... T>
    auto parse(std::string const& s) {
        using V = boost::variant<T...>;
        V v;

        auto it = s.begin();
        if (x3::parse(it, s.end(), parser_for(v), v))
            return v;
        throw std::runtime_error(std::string(__FUNCTION__) + " failed");
    }

    struct Latitude { double lat_; };
    struct Longitude { double lon_; };

    auto label_for(Latitude) { return "LAT"; }
    auto label_for(Longitude) { return "LON"; }

    template <typename T, typename P>
    auto as_cmd(P p) { return x3::rule<struct _, T>{} 
            = x3::skip(x3::space)[x3::lit(label_for(T{})) >> '=' >> p]; }

    template <typename T>    auto parser_for(T)                      { return as_cmd<T>(x3::double_); }
    template <typename... T> auto parser_for(boost::variant<T...> _) { return (parser_for(T{}) | ...); }

    static inline std::ostream& operator<<(std::ostream& os, Latitude const &t) { return os << "Latitude = " << t.lat_ << " deg"; }
    static inline std::ostream& operator<<(std::ostream& os, Longitude const &t) { return os << "Longitude = " << t.lon_ << " deg"; }
}

BOOST_FUSION_ADAPT_STRUCT(Commands::Latitude, lat_)
BOOST_FUSION_ADAPT_STRUCT(Commands::Longitude, lon_)

#include <iostream>
#include <sstream>

int main() {
    std::istringstream iss("LAT=4.3\n LON=5.0");
    std::string s;

    while (std::getline(iss, s)) try {
        using namespace Commands;
        std::cout << "Parsed '" << s << "' into " << parse<Latitude, Longitude>(s) << "\n";
    } catch (std::exception const& e) {
        std::cout << "'" << s << "': " << e.what() << "\n";
    }
}

尝试使用
rule\uu=rule\uu.copy()|…
除了将语法存储在元组中之外。谢谢,它工作得很好。你能解释一下问题是什么吗?也许会有帮助。@llonesmiz或or。不过,在这种情况下,我只需要使用自动解析器。@llonesmiz添加了一个答案,说明了这种方法非常感谢,你的解决方案非常有趣。我真正想做的是s只使用一个模板参数调用
parse
函数,因此需要一个包含各种简单语法的“容器”。嗯?好了:。即使出于某些/其他/原因,您确实需要一个
qi::grammar
实例而不是
qi::auto
,您也可以在~3行代码中添加它:()
Parsed 'LAT=4.3' into Latitude = 4.3 deg
Parsed ' LON=5.0' into Longitude = 5 deg
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace Commands {
    namespace x3 = boost::spirit::x3;
    template <typename... T>
    auto parse(std::string const& s) {
        using V = boost::variant<T...>;
        V v;

        auto it = s.begin();
        if (x3::parse(it, s.end(), parser_for(v), v))
            return v;
        throw std::runtime_error(std::string(__FUNCTION__) + " failed");
    }

    struct Latitude { double lat_; };
    struct Longitude { double lon_; };

    auto label_for(Latitude) { return "LAT"; }
    auto label_for(Longitude) { return "LON"; }

    template <typename T, typename P>
    auto as_cmd(P p) { return x3::rule<struct _, T>{} 
            = x3::skip(x3::space)[x3::lit(label_for(T{})) >> '=' >> p]; }

    template <typename T>    auto parser_for(T)                      { return as_cmd<T>(x3::double_); }
    template <typename... T> auto parser_for(boost::variant<T...> _) { return (parser_for(T{}) | ...); }

    static inline std::ostream& operator<<(std::ostream& os, Latitude const &t) { return os << "Latitude = " << t.lat_ << " deg"; }
    static inline std::ostream& operator<<(std::ostream& os, Longitude const &t) { return os << "Longitude = " << t.lon_ << " deg"; }
}

BOOST_FUSION_ADAPT_STRUCT(Commands::Latitude, lat_)
BOOST_FUSION_ADAPT_STRUCT(Commands::Longitude, lon_)

#include <iostream>
#include <sstream>

int main() {
    std::istringstream iss("LAT=4.3\n LON=5.0");
    std::string s;

    while (std::getline(iss, s)) try {
        using namespace Commands;
        std::cout << "Parsed '" << s << "' into " << parse<Latitude, Longitude>(s) << "\n";
    } catch (std::exception const& e) {
        std::cout << "'" << s << "': " << e.what() << "\n";
    }
}
Parsed 'LAT=4.3' into Latitude = 4.3 deg
Parsed ' LON=5.0' into Longitude = 5 deg