我的编程问题并不容易,因为我不知道问题出在哪里。实际上,我在boost spirit karma Library中的某个地方丢失了运行时错误。我想这里我想念一种调试技术。
我已经看到宏 BOOST_SPIRIT_DEBUG_NODE(S) 对解析器有很大帮助,尽管我在手册中找不到对它的任何引用。对于生成器,它似乎不起作用,我(老实说)没有勇气(我应该?)深入研究这个库的代码,以了解问题所在。
我试图在语法中单独生成三种类型的类似联合的结构而没有任何问题。所以我假设错误来自U结构的强制变换,再次出现(参见Casting attribute to boost::variant),但我没有证据。
对于那些可以通过简单的代码检查解决问题的人,这是我的问题的最小例子:
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/karma.hpp>
#include <boost/variant/variant.hpp>
namespace ka = boost::spirit::karma;
typedef std::back_insert_iterator<std::string> iterator;
typedef enum {A, B, C } E;
typedef enum {FOO, BAR, POINTER } K;
struct U /* Union like */
{
K kind;
double foo;
E bar;
unsigned int * p;
};
class EName : public ka::symbols<E, std::string>
{
public:
EName()
{
add (A,"A") (B,"B") (C,"C");
}
};
typedef boost::variant<E, double, unsigned int *> 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) {
switch (u.kind)
{
case FOO:
return type(u.foo);
case BAR:
return type(u.bar);
case POINTER:
return type(u.p);
}
return type(A);
}
};
}}}
class grm: public ka::grammar<iterator, U()>
{
public:
grm():grm::base_type(start)
{
start = ka::attr_cast<UVariant >(bar | foo | pointer);
bar = b;
foo = ka::double_;
pointer = ka::hex;
}
private:
ka::rule<iterator,U()> start;
ka::rule<iterator,double()> foo;
ka::rule<iterator,E()> bar;
ka::rule<iterator,unsigned int *()> pointer;
EName b;
};
int main(int argc, char * argv[])
{
grm g;
U u;
//unsigned int a;
u.kind = BAR;
//u.foo = 1.0;
u.bar = B;
//u.p = &a;
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
ka::generate(sink,g,u);
std::cout << generated;
return 0;
}
更新:编译器:Visual C ++ Express版本11和12.调用堆栈停在:
// If you are seeing a compilation error here stating that the
// third parameter can't be converted to a karma::reference
// then you are probably trying to use a rule or a grammar with
// an incompatible delimiter type.
if (f(sink, context, delim)) // <--- call stack stops here (last boost spirit reference)
此外,我发现 _SCL_SECURE_NO_WARNINGS 宏的定义遮蔽了以下编译器警告:
警告C4996:'std :: _ Copy_impl':带参数的函数调用 可能不安全 - 此调用依赖于调用者来检查 传递的值是正确的。要禁用此警告,请使用 -D_SCL_SECURE_NO_WARNINGS。请参阅有关如何使用Visual C ++'Checked Iterators'的文档
此警告涉及几个boost-spirit文件:
答案 0 :(得分:1)
I can't reproduce the error.
I can't "solve it" from a little code inspection either. I can however do two things:
I can confirm that debug macros don't appear to be implemented for Karma
I can go out on a limb and say that perhaps bar|foo|pointer
needs to be deep-copied:
start = ka::attr_cast<UVariant >(boost::proto::deep_copy(bar | foo | pointer));
I tried with UB-sanitizer and Address-sanitizer enabled, but they both didn't report any problems.
UPDATE In fact it looks like I can "solve" it from a little code inspection (and lucky brainwave) after all:
In fact, running under valgrind DOES show a problem and indeed, it goes away when adding the deep_copy
.
I'll add some references as to how I hypothesized these things:
in general: the problem with dangling references to temporaries in (Proto) expression templates
specifically the problem seen some years ago in qi::attr_cast<>
: