Я мог бы решить эту проблему для этого конкретного случая (на самом деле мы обсуждали варианты в списке ), но на самом деле, такая «загадочная» ошибка чаще появляется с Boost Spirit, и это будетнеплохо разобраться с общим классом проблем.
Ваш первый ресурс должен быть превосходной спиртовой документацией, которая точно описывает, каким будет синтезированный атрибут для данного примитива синтаксического анализатора, оператораили директива.См. справочный раздел до Spirit Qi Docs .
В некоторых случаях я перенес фокус с «попытки извлечь информацию из списка ошибок компилятора».«активно запрашивать у Духа тех типов, которые он передает».Для этого я использую метод Polymorphic Callable Type (см. Документацию Spirit / Fusion).
Вот тот, который использует специфические API GCC для довольно [sic] печати типы, которые он обнаруживает:
Функтор what_is_the_attr
#include <cxxabi.h>
#include <stdlib.h>
#include <string>
#include <iostream>
template <typename T> std::string nameofType(const T& v) {
int status;
char *realname = abi::__cxa_demangle(typeid(v).name(), 0, 0, &status);
std::string name(realname? realname : "????");
free(realname);
return name;
}
struct what_is_the_attr {
template <typename> struct result { typedef bool type; };
template <typename T> bool operator()(T& attr) const {
std::cerr << "what_is_the_attr: " << nameofType(attr) << std::endl;
return true;
}
};
Пример использования: определение типа синтезированного атрибута
. Вы можете использовать его для точного определения типа синтезированного атрибута выражения синтаксического анализатора:
template <typename Exp>
void detect_attr_type(const Exp& exp)
{
using namespace boost::spirit::qi;
const char input[] = "1 2 3 4";
auto f(std::begin(input)), l(std::end(input)-1);
bool dummy = phrase_parse(
f, l,
exp [ what_is_the_attr() ],
space);
}
( Примечание: это показывает ограничение подхода - метод предполагает, что у вас есть «иная» рабочая грамматика, и вы знаете, как передать ввод, удовлетворяющий выражению, достаточный для запуска семантического действия. В большинстве случаевэто будет верно, когда вы взламываете свой анализатор Духа, хотя )
Давайте проверим это.Например, давайте посмотрим, в чем разница между выражением средней сложности и тем же, заключенным в директиву qi::raw[]
:
int main()
{
detect_attr_type( -(int_ >> *int_) );
detect_attr_type( raw [ -(int_ >> *int_) ] );
}
Вывод:
what_is_the_attr: boost::optional<boost::fusion::vector2<int, std::vector<int, std::allocator<int> > > >
what_is_the_attr: boost::iterator_range<char const*>
Внизу мыприменим это к вопросу в ОП.
Пример использования: обнаружение типов, переданных в семантические действия
Мы могли бы использовать один и тот же объект унарной функции (what_is_the_attr
) для их обнаружения, однакосемантические действия могут принимать любое количество аргументов, поэтому нам нужно обобщить.Это было бы утомительной работой, если бы не шаблон переменной (woot! Для c ++ 0x):
struct what_are_the_arguments {
template <typename...> struct result { typedef bool type; };
template <typename... T> bool operator()(const T&... attr) const {
std::vector<std::string> names { nameofType(attr)... };
std::cerr << "what_are_the_arguments:\n\t";
std::copy(names.begin(), names.end(), std::ostream_iterator<std::string>(std::cerr, "\n\t"));
std::cerr << '\n';
return true;
}
};
Повторяется для вышеуказанного тестаслучаи показывают, что Дух на самом деле пытается назвать семантическое действие с тремя аргументами , если это возможно (как задокументировано ):
what_are_the_arguments:
boost::optional<boost::fusion::vector2<int, std::vector<int, std::allocator<int> > > >
boost::spirit::unused_type
bool
what_are_the_arguments:
boost::iterator_range<char const*>
boost::spirit::unused_type
bool
Но приятно то, что выТеперь можно применить это к любому семантическому действию:
template <typename ExpWSA> void test(const ExpWSA& exp)
{
const char input[] = "1 2 3 4";
auto f(std::begin(input)), l(std::end(input)-1);
qi::phrase_parse(f, l, exp, qi::space);
}
int main()
{
test(-(-double_ >> *int_) [ phx::bind(what_are_the_arguments(), _1, _2, _0, phx::ref(std::cout), 42) ]);
}
Печать, для этого (извините) очень надуманного примера:
what_are_the_arguments:
boost::optional<double>
std::vector<int, std::allocator<int> >
boost::fusion::vector2<boost::optional<double>, std::vector<int, std::allocator<int> > >
std::ostream
int
Применительно к OP
СинтезированныйАтрибут правила derived
равен , а не , как для int_>>int_>>int_>>int_
:
auto base_expr = int_ >> int_; // avoids assigning to struct attribute
rule<const char*, mybase(), space_type> base_ = base_expr;
test(base_ >> int_ >> int_ [ what_is_the_attr() ] );
test(base_expr >> int_ >> int_ [ what_is_the_attr() ] );
Будет напечатано
what_is_the_attr: boost::fusion::vector3<mybase, int, int>
what_is_the_attr: boost::fusion::vector4<int, int, int, int>
Проблема возникла.Мы обсудили некоторые обходные пути, основанные на этой диагностике, в оригинальной ветке (и другие ответы здесь).Но этот пост должен помочь ответить на вопрос общего случая.
Полный список кодов
В интегрированной форме, скомпилированный с gcc 4.6.1 --std = c ++ 0x и boost 1_48:
#include <cxxabi.h>
#include <iostream>
#include <iterator>
#include <stdlib.h>
#include <string>
#include <vector>
template <typename T> std::string nameofType(const T& v)
{
int status;
char *realname = abi::__cxa_demangle(typeid(v).name(), 0, 0, &status);
std::string name(realname? realname : "????");
free(realname);
return name;
}
struct what_is_the_attr {
template <typename> struct result { typedef bool type; };
template <typename T> bool operator()(T& attr) const {
std::cerr << "what_is_the_attr: " << nameofType(attr) << std::endl;
return true;
}
};
struct what_are_the_arguments {
template <typename...> struct result { typedef bool type; };
template <typename... T> bool operator()(const T&... attr) const {
std::vector<std::string> names { nameofType(attr)... };
std::cerr << "what_are_the_arguments:\n\t";
std::copy(names.begin(), names.end(), std::ostream_iterator<std::string>(std::cerr, "\n\t"));
std::cerr << '\n';
return true;
}
};
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
struct mybase { int a,b; };
struct myderived : mybase { int c,d; };
BOOST_FUSION_ADAPT_STRUCT(mybase, (int,a)(int,b));
BOOST_FUSION_ADAPT_STRUCT(myderived, (int,a)(int,b)(int,c)(int,d));
template <typename ExpWSA>
void test(const ExpWSA& exp)
{
using namespace boost::spirit::qi;
const char input[] = "1 2 3 4";
auto f(std::begin(input)), l(std::end(input)-1);
bool dummy = phrase_parse(f, l, exp, space);
}
int main()
{
using namespace boost::spirit::qi;
// Diagnostics for the OP case
auto base_expr = int_ >> int_; // avoids assigning to struct attribute
rule<const char*, mybase(), space_type> base_ = base_expr;
// Derived rule, different formulations
test((base_ >> int_ >> int_) [ what_is_the_attr() ] );
test((base_expr >> int_ >> int_) [ what_is_the_attr() ] );
// Applied to attribute types
test(raw [ -(int_ >> *int_) ] [ what_is_the_attr() ] );
test(-(int_ >> *int_) [ what_is_the_attr() ] );
// applied to semantic actions - contrived example
namespace phx = boost::phoenix;
test(-(-double_ >> *int_) [ phx::bind(what_are_the_arguments(), _1, _2, _0, phx::ref(std::cout), 42) ]);
return 0;
}