【问题标题】:casting attribute to boost::variant将属性转换为 boost::variant
【发布时间】:2016-07-04 20:22:12
【问题描述】:

在学习如何使用 boost spirit、phoenix 和 fusion 库时,我遇到了这个无法在 msvc(2015,版本 14)和 boost 1.61.0 上编译的最小示例

#include <boost/spirit/include/karma.hpp>
#include <boost/variant/variant.hpp>

namespace ka = boost::spirit::karma;

struct U /* a kind of union (legacy code)*/
    {
        bool kind;
        double foo; /* if kind = true */
        size_t bar; /* if kind = false */
    };

typedef boost::variant<double, size_t> UVariant;

namespace boost { namespace spirit { namespace traits {
    template<>
    struct transform_attribute<U,UVariant,ka::domain>
    {
        typedef UVariant type;
        static type pre(U & u) { 
            switch (u.kind)
            { 
            case true: 
                return type(u.foo); 
            case false: 
                return type(u.bar);
            }
        }
    };
}}}

typedef std::back_insert_iterator<std::string> iterator;

class grm: public ka::grammar<iterator, U()>
{
public:
    grm():grm::base_type(start)
    {
        start = ka::attr_cast<U,UVariant >(foo | bar);
        foo = ka::double_;
        bar = ka::uint_;
        */
    }
private:
    ka::rule<iterator,U()> start;
    ka::rule<iterator,double()> foo;
    ka::rule<iterator,size_t()> bar;
};

int main(int argc, char * argv[])
{
    grm g;
    U u;
    u.kind = true;
    u.foo = 1.0;

    std::string generated;
    std::back_insert_iterator<std::string> sink(generated);
    ka::generate(sink,g,u);


    return 0;
}

然后我收到以下错误消息:

错误 C2665: 'boost::detail::variant::make_initializer_node::apply::initializer_node::initialize': 5 个重载中没有一个可以转换所有参数类型

here 报告了一个类似的问题,尽管我不明白答案是如何解决这个问题的,以及这是否真的是同一个问题,因为似乎所有类型都正确提供(不需要类型转换)。

【问题讨论】:

    标签: c++ boost boost-variant boost-spirit-karma


    【解决方案1】:

    问题似乎是 Spirit 没有选择您的自定义 transform_attribute 自定义点。它使用的是默认值,它试图从const U(!!) 构造一个boost::variant&lt;double,size_t&gt;,这显然失败了。

    Karma 始终在内部使用 const 值,因此您需要将 transform_attribute 的专业化更改为:

    namespace boost { namespace spirit { namespace traits {
        template<>
        struct transform_attribute<const U,UVariant,ka::domain>
                                   ^^^^^^^
        {
            typedef UVariant type;
            static type pre(const U & u) {
                            ^^^^^^^ 
                //same as before
            }
        };
    }}}
    

    然后它会被 Karma 拾取,一切都会正常工作。

    完整示例 (On rextester):

    #include <boost/spirit/include/karma.hpp>
    #include <boost/variant/variant.hpp>
    
    namespace ka = boost::spirit::karma;
    
    struct U /* a kind of union (legacy code)*/
        {
            bool kind;
            double foo; /* if kind = true */
            size_t bar; /* if kind = false */
        };
    
    typedef boost::variant<double, size_t> UVariant;
    
    namespace boost { namespace spirit { namespace traits {
        template<>
        struct transform_attribute<const U,UVariant,ka::domain>
        {
            typedef UVariant type;
            static type pre(const U & u) { 
                if(u.kind)
                { 
                    return type(u.foo); 
                }
                else
                {
                    return type(u.bar);
                }
            }
        };
    }}}
    
    typedef std::back_insert_iterator<std::string> iterator;
    
    class grm: public ka::grammar<iterator, U()>
    {
    public:
        grm():grm::base_type(start)
        {
            start = ka::attr_cast< UVariant >(foo | bar);
            foo = ka::double_;
            bar = ka::uint_;
        }
    private:
        ka::rule<iterator,U()> start;
        ka::rule<iterator,double()> foo;
        ka::rule<iterator,size_t()> bar;
    };
    
    int main(int argc, char * argv[])
    {
        grm g;
        U u;
        u.kind = false;
        u.foo = 1.0;
        u.bar = 34;
    
        std::string generated;
        std::back_insert_iterator<std::string> sink(generated);
        ka::generate(sink,g,u);
    
        std::cout << generated << std::endl;
    
    
        return 0;
    }
    

    【讨论】:

    • 它完成了工作,谢谢。您是否根据经验或仔细检查编译器的 x ko 错误消息知道这一点?
    • Clang 的错误信息非常清楚,这对我有帮助。包含的确切错误:in instantiation of member function 'boost::spirit::karma::transform_attribute&lt;const U, boost::variant&lt;double, unsigned long&gt;, void&gt;::pre' requested here.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 2013-06-14
    相关资源
    最近更新 更多