атрибут приведения к бусту :: вариант

Изучая, как использовать библиотеки Boost, 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:
‘Повышение :: подробнее :: вариант :: make_initializer_node :: применять :: initializer_node :: инициализации’:
ни одна из 5 перегрузок не может преобразовать все типы аргументов

О подобной проблеме сообщалось Вот хотя я не мог понять, как ответ решает проблему и действительно ли это та же самая проблема, поскольку кажется, что все типы предоставлены правильно (нет необходимости в преобразовании типов).

1

Решение

Проблема, кажется, в том, что Дух не выбирает твой обычай transform_attribute пункт настройки. Он использует по умолчанию, и он пытается построить boost::variant<double,size_t> из const U(!!) и это, очевидно, не удается.

Карма всегда внутренне работает с константными значениями, поэтому вам нужно изменить свою специализацию 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
}
};
}}}

и тогда это будет подхвачено Кармой, и все будет работать.

Полный образец (На ректестере):

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

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector