1

ブースト スピリット、フェニックス、およびフュージョン ライブラリの使用方法を学習しているときに、msvc (2015、バージョン 14) およびブースト 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 つのオーバーロードのどれもすべての引数の型を変換できませんでした

同様の問題がここで報告されていますが、回答が問題にどのように対処するか、およびすべての型が正しく提供されているように見えるのでこれが本当に同じ問題であるかどうかはわかりませんでした (型変換の必要はありません)。

4

1 に答える 1

1

問題は、Spirit がカスタムtransform_attributeカスタマイズ ポイントを選択していないようです。boost::variant<double,size_t>デフォルトのものを使用しており、(!!)から aを構築しようとしていますconst Uが、明らかに失敗しています。

transform_attributeKarma は常に内部的に const 値で動作するため、特殊化を次のように変更する必要があります。

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

その後、カルマがそれを拾い上げ、すべてが機能します。

完全なサンプル ( 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;
}
于 2016-07-05T06:32:02.193 に答える