将属性强制转换为boost :: variant [英] casting attribute to boost::variant

查看:367
本文介绍了将属性强制转换为boost :: variant的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在学习如何使用boost精灵,phoenix和融合库,我来到这个最小的例子,不编译msvc(2015,版本14)和提高1.61.0

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

命名空间ka = boost :: spirit :: karma;

struct U / *一种联合(遗留代码)* /
{
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:
返回类型(u.bar);
}
}
};
}}}

typedef std :: back_insert_iterator< std :: string>迭代器

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

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

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


return 0;
}

然后我得到以下错误信息:


错误C2665:
'boost :: detail :: variant :: make_initializer_node :: apply :: initializer_node :: initialize':
5个重载可以转换所有参数类型: / 17270527 / ambiguous-variant-and-boost-spirit-x3>这里虽然我不明白如何解答这个问题,是否这是真的是一样的问题,似乎所有类型都正确提供(没有问题似乎是Spirit不选择你的自定义需要类型转换。

解决方案

transform_attribute 自定义点。它使用默认值,并尝试从 const U boost :: variant< double,size_t> >



Karma总是在内部使用const值,所以你需要改变你的特殊化 transform_attribute to:

  namespace boost {namespace spirit {namespace traits {
template<
struct transform_attribute< const U,UVariant,ka :: domain>
^^^^^^^
{
typedef UVariant type;
static type pre(const U& u){
^^^^^^^
//与之前相同
}
};
}}}

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



完整示例(关于rextester ):

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

命名空间ka = boost :: spirit :: karma;

struct U / *一种联合(遗留代码)* /
{
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>迭代器

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()>开始;
ka :: rule< iterator,double()> foo;
ka :: rule< iterator,size_t()>酒吧;
};

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

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

std :: cout<<生成< std :: endl;


return 0;
}


While learning how to use boost spirit, phoenix and fusion libraries, I came accross this minimal example that does not compile on msvc (2015, version 14) and 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;
}

Then I get the following error message:

error C2665: 'boost::detail::variant::make_initializer_node::apply::initializer_node::initialize' : none of the 5 overloads could convert all arguments types

A similar issue has been reported here although I could not understand how the answer address the issue and whether this is really the same issue as it seems all types are correctly provided (no need for type conversions).

解决方案

The problem seems to be that Spirit isn't picking your custom transform_attribute customization point. It's using the default one, and that tries to construct a boost::variant<double,size_t> from a const U(!!) and that obviously fails.

Karma always works with const values internally so you need to change your specialization of transform_attribute to:

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
        }
    };
}}}

and then it will be picked up by Karma and everything will work.

Full sample (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;
}

这篇关于将属性强制转换为boost :: variant的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆