我试图用boost::variant
内boost::optional
的噶发电机。我已经能够将问题减少为:
using FooVariant = boost::variant<int>;
using FooOptional = boost::optional<FooVariant>;
template<typename OutputIt = boost::spirit::ostream_iterator>
struct FooGenerator
: boost::spirit::karma::grammar<OutputIt, FooOptional()>
{
FooGenerator()
: FooGenerator::base_type(start_)
{
namespace bsk = boost::spirit::karma;
start_ = '[' << ( bsk::int_ | '*' ) << ']';
}
boost::spirit::karma::rule<OutputIt, FooOptional()> start_;
};
int main()
{
FooOptional fop1;
std::cout << boost::spirit::karma::format(FooGenerator<>(), fop1) << std::endl;
FooOptional fop2 = FooVariant{123};
std::cout << boost::spirit::karma::format(FooGenerator<>(), fop2) << std::endl;
}
输出是:
[*]
[*]
这不是我想要的。
的第一件事情,我改变了或多或少完整性检查通过改变FooVariant
来:using FooVariant = int;
。输出:
[*]
[123]
而且就是我想看的!因此,在我的第一个代码中,变体只有一个类型,因此我尝试添加第二个类型,以查看:
using FooVariant = boost::variant<int, double>;
...
start_ = '[' << ( ( bsk::int_ | bsk::double_ ) | '*' ) << ']';
但是,然后我们回到:
[*]
[*]
然后,我尝试为该变体添加专门的规则:
using FooVariant = boost::variant<int, double>;
using FooOptional = boost::optional<FooVariant>;
template<typename OutputIt = boost::spirit::ostream_iterator>
struct FooGenerator
: boost::spirit::karma::grammar<OutputIt, FooOptional()>
{
FooGenerator()
: FooGenerator::base_type(start_)
{
namespace bsk = boost::spirit::karma;
foovar_ = (bsk::int_ | bsk::double_);
start_ = '[' << ( foovar_ | '*' ) << ']';
}
boost::spirit::karma::rule<OutputIt, FooVariant()> foovar_;
boost::spirit::karma::rule<OutputIt, FooOptional()> start_;
};
int main()
{
FooOptional fop1;
std::cout << boost::spirit::karma::format(FooGenerator<>(), fop1) << std::endl;
FooOptional fop2 = FooVariant{123};
std::cout << boost::spirit::karma::format(FooGenerator<>(), fop2) << std::endl;
}
给出编译错误:
alternative_function.hpp:127:34: error: no member named 'is_compatible' in
'boost::spirit::traits::compute_compatible_component<boost::variant<int, double>, boost::optional<boost::variant<int, double> >, boost::spirit::karma::domain>'
if (!component_type::is_compatible(spirit::traits::which(attr_)))
~~~~~~~~~~~~~~~~^
看起来模板生成正在尝试确保boost::variant
和boost::optional
兼容,但对我来说,问题是“为什么要尝试确保它们完全兼容?”
我该如何工作?
我在另一个答案中告诉您如何处理:Boost Karma:未设置boost :: optional时生成默认文本
这不仅回避了问题,而且还简化了AST /数据类型。
现在,由于您要强迫我¹,我挖了一下。问题出在foovar_ | '|'
一个替代表达式这一事实上,它以某种方式验证了该属性必须兼容。在检查过程中,假设
a
具有属性attr(a)
并且b
具有属性,attr(b)
则a | b
应该有 variant<attr(a), attr(b)
它确实进行了一些逻辑检查(例如when attr(a) == attr(b)
),但没有进行逻辑检查,如果它attr(b)
是unused_type
那么那么应该与optional<attr(a)>
too兼容,而不是仅仅与variant<attr(a), unused_type>
even甚至兼容variant<attr(a)>
。
现在,为什么对我没那么感兴趣²。因此,这是强制执行操作的方法。
foovar_ = bsk::int_ | bsk::double_;
fooopt_ = (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_;
start_ = '[' << fooopt_ << ']';
的关键是将其编码为比其他的东西替代表达。在这里,我们只是相信-foovar_
说些什么而已。此外,我们也
bsk::eps(is_initialized_(bsk::_val)) | '*'
含义:如果变体已初始化,仅此而已,否则,请生成'*'
。
现在,您完全不需要第三条规则,如果您喜欢只写代码,则可以编写:
start_ = '[' << (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_ << ']';
哦,我几乎忘记了:
struct is_initialized_f {
template<typename T>
bool operator()(boost::optional<T> const& opt) const { return opt.is_initialized(); }
};
boost::phoenix::function<is_initialized_f> is_initialized_;
实现该助手Phoenix演员以检查初始化状态。
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
using FooVariant = boost::variant<int, double>;
using FooOptional = boost::optional<FooVariant>;
template<typename OutputIt = boost::spirit::ostream_iterator>
struct FooGenerator
: boost::spirit::karma::grammar<OutputIt, FooOptional()>
{
FooGenerator()
: FooGenerator::base_type(start_)
{
namespace bsk = boost::spirit::karma;
namespace phx = boost::phoenix;
foovar_ = bsk::int_ | bsk::double_;
//fooopt_ = (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_;
start_ = '[' << (bsk::eps(is_initialized_(bsk::_val)) | '*') << -foovar_ << ']';
}
private:
struct is_initialized_f {
template<typename T>
bool operator()(boost::optional<T> const& opt) const { return opt.is_initialized(); }
};
boost::phoenix::function<is_initialized_f> is_initialized_;
boost::spirit::karma::rule<OutputIt, FooVariant()> foovar_;
//boost::spirit::karma::rule<OutputIt, FooOptional()> fooopt_;
boost::spirit::karma::rule<OutputIt, FooOptional()> start_;
};
int main()
{
for (FooOptional fop : { FooOptional{}, {FooVariant{123}}, {FooVariant{3.14}} }) {
if (std::cout << boost::spirit::karma::format(FooGenerator<>(), fop))
std::cout << "\n";
else
{
std::cout.clear();
std::cout << "#Error\n";
}
}
}
版画
[*]
[123]
[3.14]
¹笑话
²我们将获得与“有人忘了”或“这是回归”押韵的非权威性答案
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句