In order to prevent the compiler to apply e.g. a std::vector<T> to a statement like std::cout << u, I would like to do something like this:
if constexpr (std::has_output_operator<U>) {
std::cout << u;
}
Is there some way to achieve this?
EDIT (clarification)
I am working on printf-like function which can also print strings and vectors of POD and strings (and vectors thereof).
I would like to extend this functionality to any type which has an output operator.
The actual formatting for non-vector types is done by the functions simpleFormat():
// simpleFormat
// special case for single string
//
std::string simpleFormat(const std::string sFormat, const std::string t) {
size_t required = snprintf(NULL, 0, sFormat.c_str(), t.c_str());
char sTemp[required+1];
sprintf(sTemp, sFormat.c_str(), t.c_str());
return std::string(sTemp);
}
// simpleFormat
// catch for vectors (should not be sent to simpleFormat)
template<typename T>
std::string simpleFormat(const std::string sFormat, const std::vector<T> t) {
return "";
}
// simpleFormat
// formatting PODs and Objects with output operator a char using
template<typename T>
std::string simpleFormat(const std::string sFormat, const T t) {
std::string sRes = "";
if (sFormat.size() > 0) {
if (sFormat != "%O") {
size_t required = snprintf(NULL, 0, sFormat.c_str(), t);
char sTemp[required+1];
sprintf(sTemp, sFormat.c_str(), t);
sRes = std::string(sTemp);
} else {
std::stringstream ss("");
ss << t;
sRes += ss.str();
}
}
return sRes;
}
When i compile this for some applications, get the error
In file included from AgentCounter.cpp:6:
../utils/stdstrutilsT.h: In instantiation of ‘std::string simpleFormat(std::string, T) [with T = __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; std::string = std::__cxx11::basic_string<char>]’:
../utils/stdstrutilsT.h:195:33: required from ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; Args = {long long unsigned int}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’
../utils/stdstrutilsT.h:281:31: required from ‘std::string stdsprintf(std::string, Args ...) [with Args = {__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, long long unsigned int}; std::string = std::__cxx11::basic_string<char>]’
../utils/stdstrutilsT.h:291:34: required from ‘void stdprintf(std::string, Args ...) [with Args = {__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, long long unsigned int}; std::string = std::__cxx11::basic_string<char>]’
AgentCounter.cpp:326:22: required from here
../utils/stdstrutilsT.h:165:28: error: no match for ‘operator<<’ (operand types are ‘std::stringstream’ {aka ‘std::__cxx11::basic_stringstream<char>’} and ‘const __gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >’)
165 | ss << t;
| ~~~^~~~
Even though i have a simpleFormat() variant for vectors, the compiler still wants to fit the std::vector into the POD variant.
That is why i hope there is constexpr which lets me find out if the passed type has an output operator.
Of course if there are other possibilities to stop the compiler from applying vectors to my non-vector function, i'd like to learn about them.
This can be done straightforwardly using the C++20 requires-expression, which checks whether its operand is valid:
if constexpr (requires { std::cout << u; })
You can also define a named concept with the requires-expression and then use it in place of the requires-expression every time you need it.
I'm clearly missing something here, but what?
Definition (... denotes valid code, not actual three points):
class CrmxFile {
private:
const std::vector<std::string> validValues;
int value;
public:
void setValue(std::string _value);
...
}
std::vector<std::string> CrmxFile = {...};
In the code I have this:
void Crmx::SetValue(std::string _value) {
std::vector<std::string>::iterator idx;
if((idx = std::find(validValues.begin(), validValues.end(), _value)) == validValues.end()) {
value = 0;
}
else {
value = idx - validValues.begin();
}
}
I compile this with gcc -c -std=c++0x and I get this error:
CrmxFile.cpp: In member function ‘void CrmxFile::SetValue(std::string)’:
CrmxFile.cpp:24:64: error: no match for ‘operator=’ in ‘idx = std::find [with _IIter = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >, _Tp = std::basic_string<char>](Id3V1::validValues.std::vector<_Tp, _Alloc>::begin [with _Tp = std::basic_string<char>, _Alloc = std::allocator<std::basic_string<char> >, std::vector<_Tp, _Alloc>::const_iterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_pointer = const std::basic_string<char>*](), Id3V1::validValues.std::vector<_Tp, _Alloc>::end [with _Tp = std::basic_string<char>, _Alloc = std::allocator<std::basic_string<char> >, std::vector<_Tp, _Alloc>::const_iterator = __gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::const_pointer = const std::basic_string<char>*](), (*(const std::basic_string<char>*)(& _value)))’
CrmxFile.cpp:24:64: note: candidates are:
/usr/include/c++/4.6/bits/stl_iterator.h:702:11: note: __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >& __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >::operator=(const __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >&)
/usr/include/c++/4.6/bits/stl_iterator.h:702:11: note: no known conversion for argument 1 from ‘__gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >’ to ‘const __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >&’
/usr/include/c++/4.6/bits/stl_iterator.h:702:11: note: __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >& __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >::operator=(__gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >&&)
/usr/include/c++/4.6/bits/stl_iterator.h:702:11: note: no known conversion for argument 1 from ‘__gnu_cxx::__normal_iterator<const std::basic_string<char>*, std::vector<std::basic_string<char> > >’ to ‘__gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >&&’
What am I missing? Or, alternatively, is there a better way of finding the index of a given value in a vector?
idx has to be a const_iterator since validValues is a const vector<...>.
std::vector<std::string>::const_iterator idx;
Since validValues is const, begin(), end(), and therefore this instantiation of std::find, all return std::vector<std::string>::const_iterator, not std::vector<std::string>::iterator. For const-safety, a const_iterator cannot convert to an iterator.
validValues is defined as const std::vector<std::string>. Therefore begin() and end() will return const_iterator, but you are trying to assign the result to a iterator. Converting a const_iterator to an iterator would break const correctness (since you could then go on and change the underlying object) and is therefore not allowed.
Change the definition of idx to be std::vector<std::string>::const_iterator and it should work.
"What am I missing?"
Is yours first validValues invalid?
I suggest:
void Crmx::SetValue(std::string _value) {
value = std::find(validValues.begin(), validValues.end(), _value) - validValues.begin();
}
and use the validValues.size as invalid value, not 0
there. I've searched my question around here but failed to find anything relevant.
This is the problem.
I have this code in the part of my program, doing kind of stupid sort by inserts.
I developed that in MSVS 2008 and it all worked fine, but when I tried to compile that with g++, it failed because of list::insert function below;
//...
pair<uint, double> NewElem(i, Prob.at(i));
bool inserted(false);
vector<pair<uint, double> >::const_iterator li = NewList.begin();
for ( vector<double>::const_iterator ji = BlocksMemory.begin() ; ji != BlocksMemory.end() ; ++ji)
{
if (NewElem.second <= *ji)
li += _SORT_BLOCK;
else
break;
}
for(;li != NewList.end() ; ++li)
{
if (NewElem.second > li->second)
{
NewList.insert(li, NewElem );
inserted = true;
break;
}
}
as one can see, li is const_iterator of NewList;
And NewElem has type pair with the same content type as NewList contents;
There you can see the response (unreadable):
main.cpp:447: error: no matching function for call to "std::vector<std::pair<unsigned int, double>, std::allocator<std::pair<unsigned int, double> > >::insert(__gnu_cxx::__normal_iterator<const std::pair<unsigned int, double>*, std::vector<std::pair<unsigned int, double>, std::allocator<std::pair<unsigned int, double> > > >&, std::pair<unsigned int, double>&)"
/usr/include/c++/4.4/bits/vector.tcc:106: note: candidates are: __gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp, _Alloc>::insert(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::pair<unsigned int, double>, _Alloc = std::allocator<std::pair<unsigned int, double> >]
/usr/include/c++/4.4/bits/stl_vector.h:850: note: void std::vector<_Tp, _Alloc>::insert(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, size_t, const _Tp&) [with _Tp = std::pair<unsigned int, double>, _Alloc = std::allocator<std::pair<unsigned int, double> >]
What can be the reason? And what is the possible solution?
The signature of the insert member function that you are trying to use is probably:
iterator insert( iterator, const value_type& );
But the first argument that you are passing to the function is a const_iterator, that cannot be implicitly converted to a non const iterator. That code should not have worked on VS either.
The simple solution is that if you intend to modify the container you use a non-const iterator: define li as std::vector< std::pair<uint,double> >::iterator li = NewList.begin();
Also, are you sure that you want to be inserting into a std::vector? For performance reasons, a std::list would be a better choice. Also, an insert on a list doesn't invalidate existing iterators as it does for a vector.
I'm having issues getting a small spirit/qi grammar to compile. The build stack trace is fugly enought to not make any sense to me (despite some assertion_failed i could notice in there but that didn't brought much information)
the input grammar header:
inputGrammar.h
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
namespace sp = boost::spirit;
namespace qi = boost::spirit::qi;
using namespace boost::spirit::ascii;
//using namespace boost::spirit::arg_names;
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
using phoenix::at_c;
using phoenix::push_back;
template< typename Iterator , typename ExpressionAST >
struct InputGrammar : qi::grammar<Iterator, ExpressionAST(), space_type> {
InputGrammar() : InputGrammar::base_type( block ) {
tag = sp::lexeme[+(alpha) [sp::_val += sp::_1]];//[+(char_ - '<') [_val += _1]];
block = sp::lit("block") [ at_c<0>(sp::_val) = sp::_1]
>> "(" >> *instruction[ push_back( at_c<1>(sp::_val) , sp::_1 ) ]
>> ")";
command = tag [ at_c<0>(sp::_val) = sp::_1]
>> "(" >> *instruction [ push_back( at_c<1>(sp::_val) , sp::_1 )]
>> ")";
instruction = ( command | tag ) [sp::_val = sp::_1];
}
qi::rule< Iterator , std::string() , space_type > tag;
qi::rule< Iterator , ExpressionAST() , space_type > block;
qi::rule< Iterator , ExpressionAST() , space_type > function_def;
qi::rule< Iterator , ExpressionAST() , space_type > command;
qi::rule< Iterator , ExpressionAST() , space_type > instruction;
};
the test build program:
i seems the build fails at qi::phrase_parse, i am using boost 1.43 and g++ 4.4.1
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//my grammar
#include <InputGrammar.h>
struct MockExpressionNode {
std::string name;
std::vector< MockExpressionNode > operands;
typedef std::vector< MockExpressionNode >::iterator iterator;
typedef std::vector< MockExpressionNode >::const_iterator const_iterator;
iterator begin() { return operands.begin(); }
const_iterator begin() const { return operands.begin(); }
iterator end() { return operands.end(); }
const_iterator end() const { return operands.end(); }
bool is_leaf() const {
return ( operands.begin() == operands.end() );
}
};
BOOST_FUSION_ADAPT_STRUCT(
MockExpressionNode,
(std::string, name)
(std::vector<MockExpressionNode>, operands)
)
int const tabsize = 4;
void tab(int indent)
{
for (int i = 0; i < indent; ++i)
std::cout << ' ';
}
template< typename ExpressionNode >
struct ExpressionNodePrinter
{
ExpressionNodePrinter(int indent = 0)
: indent(indent)
{
}
void operator()(ExpressionNode const& node) const {
cout << " tag: " << node.name << endl;
for (int i=0 ; i < node.operands.size() ; i++ ) {
tab( indent ); cout << " arg "<<i<<": "; ExpressionNodePrinter(indent + 2)( node.operands[i]); cout << endl;
}
}
int indent;
};
int test() {
MockExpressionNode root;
InputGrammar< string::const_iterator , MockExpressionNode > g();
std::string litA = "litA";
std::string litB = "litB";
std::string litC = "litC";
std::string litD = "litD";
std::string litE = "litE";
std::string litF = "litF";
std::string source = litA+"( "+litB+" ,"+litC+" , "+ litD+" ( "+litE+", "+litF+" ) "+ " )";
string::const_iterator iter = source.begin();
string::const_iterator end = source.end();
bool r = qi::phrase_parse( iter , end , g , root , space );
ExpressionNodePrinter< MockExpressionNode > np;
np( root );
};
int main() {
test();
}
finally, the build error is the following:
/usr/bin/make -f nbproject/Makefile-linux_amd64_devel.mk SUBPROJECTS= .build-conf
make[1]: se ingresa al directorio `/home/mineq/NetBeansProjects/InputParserTests'
/usr/bin/make -f nbproject/Makefile-linux_amd64_devel.mk dist/linux_amd64_devel/GNU-Linux-x86/vpuinputparsertests
make[2]: se ingresa al directorio `/home/mineq/NetBeansProjects/InputParserTests'
mkdir -p build/linux_amd64_devel/GNU-Linux-x86
rm -f build/linux_amd64_devel/GNU-Linux-x86/tests_main.o.d
g++ `llvm-config --cxxflags` `pkg-config --cflags unittest-cpp` `pkg-config --cflags boost-1.43` `pkg-config --cflags boost-coroutines` -c -g -I../InputParser -MMD -MP -MF build/linux_amd64_devel/GNU-Linux-x86/tests_main.o.d -o build/linux_amd64_devel/GNU-Linux-x86/tests_main.o tests_main.cpp
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/auto.hpp:16,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi.hpp:15,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/include/qi.hpp:16,
from ../InputParser/InputGrammar.h:12,
from tests_main.cpp:14:
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp: In function ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>]’:
In file included from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/detail/parse_auto.hpp:14,
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:125: instantiated from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::spirit::ascii::space_type]’
tests_main.cpp:206: instantiated from here
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:99: error: no matching function for call to ‘assertion_failed(mpl_::failed************ (boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>]::error_invalid_expression::************)(InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode> (*)()))’
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:125: instantiated from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::spirit::ascii::space_type]’
tests_main.cpp:206: instantiated from here
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:100: error: no matching function for call to ‘assertion_failed(mpl_::failed************ (boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>]::error_invalid_expression::************)(MockExpressionNode))’
from /home/mineq/third_party/boost_1_43_0/boost/proto/proto.hpp:12,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/support/meta_compiler.hpp:17,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/meta_compiler.hpp:14,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/action/action.hpp:14,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/action.hpp:14,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi.hpp:14,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/include/qi.hpp:16,
from ../InputParser/InputGrammar.h:12,
from tests_main.cpp:14:
/home/mineq/third_party/boost_1_43_0/boost/proto/detail/expr0.hpp: At global scope:
/home/mineq/third_party/boost_1_43_0/boost/proto/proto_fwd.hpp: In instantiation of ‘boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>()>, 0l>’:
In file included from /home/mineq/third_party/boost_1_43_0/boost/proto/core.hpp:13,
/home/mineq/third_party/boost_1_43_0/boost/utility/enable_if.hpp:59: instantiated from ‘boost::disable_if<boost::proto::result_of::is_expr<boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>()>, 0l>, void>, void>’
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/support/meta_compiler.hpp:200: instantiated from ‘boost::spirit::result_of::compile<boost::spirit::qi::domain, InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), boost::fusion::unused_type, void>’
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:107: instantiated from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>]’
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:125: instantiated from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::spirit::ascii::space_type]’
tests_main.cpp:206: instantiated from here
/home/mineq/third_party/boost_1_43_0/boost/proto/detail/expr0.hpp:64: error: field ‘boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>()>, 0l>::child0’ invalidly declared function type
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/auto.hpp:16,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi.hpp:15,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/include/qi.hpp:16,
from ../InputParser/InputGrammar.h:12,
from tests_main.cpp:14:
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp: In function ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>]’:
In file included from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/detail/parse_auto.hpp:14,
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:125: instantiated from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::spirit::ascii::space_type]’
tests_main.cpp:206: instantiated from here
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:107: error: request for member ‘parse’ in ‘boost::spirit::compile [with Domain = boost::spirit::qi::domain, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>()](((InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode> (&)())((InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode> (*)())expr)))’, which is of non-class type ‘InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>()’
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/auto.hpp:15,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi.hpp:15,
from /home/mineq/third_party/boost_1_43_0/boost/spirit/include/qi.hpp:16,
from ../InputParser/InputGrammar.h:12,
from tests_main.cpp:14:
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/skip_over.hpp: In function ‘void boost::spirit::qi::skip_over(Iterator&, const Iterator&, const T&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, T = boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>]::skipper_type]’:
In file included from /home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/auto/auto.hpp:19,
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:112: instantiated from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>]’
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/parse.hpp:125: instantiated from ‘bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&, const Skipper&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Expr = InputGrammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, MockExpressionNode>(), Skipper = MockExpressionNode, Attr = const boost::spirit::ascii::space_type]’
tests_main.cpp:206: instantiated from here
/home/mineq/third_party/boost_1_43_0/boost/spirit/home/qi/skip_over.hpp:27: error: ‘const struct MockExpressionNode’ has no member named ‘parse’
make[2]: *** [build/linux_amd64_devel/GNU-Linux-x86/tests_main.o] Error 1
make[2]: se sale del directorio `/home/mineq/NetBeansProjects/InputParserTests'
make[1]: *** [.build-conf] Error 2
make[1]: se sale del directorio `/home/mineq/NetBeansProjects/InputParserTests'
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 1m 48s)
The attribute(s) always have to be passed as the last parameter(s) to the parse/phrase_parse functions. So you need to write:
bool r = qi::phrase_parse( iter , end , g , space, root );
Further, you can remove all semantic actions from your grammar if you add additional constructors to the ExpressionAST type:
template< typename Iterator , typename ExpressionAST >
struct InputGrammar : qi::grammar<Iterator, ExpressionAST(), space_type> {
InputGrammar() : InputGrammar::base_type( block ) {
tag = sp::lexeme[+(alpha)];
block = sp::lit("block") >> "(" >> *instruction >> ")";
command = tag >> "(" >> *instruction >> ")";
instruction = ( command | tag );
}
qi::rule< Iterator , std::string() , space_type > tag;
qi::rule< Iterator , ExpressionAST() , space_type > block;
qi::rule< Iterator , ExpressionAST() , space_type > function_def;
qi::rule< Iterator , ExpressionAST() , space_type > command;
qi::rule< Iterator , ExpressionAST() , space_type > instruction;
};
and
struct MockExpressionNode {
// ...
MockExpressionNode() {}
MockExpressionNode(std::string name) : name(name) {}
// ...
};
But even then it won't compile because the MockExpressionNode data structure is self-recursive. This can be fixed by either storing a vector of pointers (which requires to changethe grammar) or by using boost::recursive_wrapper.