Parsing a structure in an associative manner with Boost Spirit and Fusion - c++

I'm trying to parse a key-value string into a structure. Some key-values may be absent or may be in different order, so I wanted to use boost::fusion to adapt the structure and then parse into it with at_key<> directive.
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/sequence.hpp>
using namespace std;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;
using boost::fusion::at_key;
typedef string::const_iterator iter_type;
struct Couple {
int a;
int b;
Couple() : a(0), b(0) {}
};
namespace keys {
struct first;
struct second;
}
BOOST_FUSION_ADAPT_ASSOC_STRUCT(
Couple,
(int, a, keys::first)
(int, b, keys::second)
)
struct G: qi::grammar< iter_type, Couple(), ascii::space_type >
{
G() : G::base_type( start_rule ) {
using qi::_val;
using qi::_1;
using qi::_2;
start_rule =
( "first" >> qi::int_
[ at_key<keys::first>(_val) = _1 ]
)
^
( "second" >> qi::int_
[ at_key<keys::second>(_val) = _1 ]
);
}
qi::rule< iter_type, Couple(), ascii::space_type > start_rule;
};
int main() {
Couple couple;
string example = "second 2 first 1";
iter_type begin( example.begin() );
iter_type end( example.end() );
// test at_key -- compiles with no error
at_key<keys::second>(couple) = 5;
bool ok = qi::phrase_parse( begin, end, G(), ascii::space, couple );
if ( ok )
cout << couple.a << " " << couple.b << endl;
else
cout << "Parse failed" << endl;
return 0;
}
The problem is that the code does not compile (Boost 1.50.0, g++ 4.5.0, MinGW), apparently fails at the at_key<> rules:
In file included from D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:10:0,
from D:\projects\workspace\boost/boost/fusion/include/category_of.hpp:10,
from D:\projects\workspace\boost/boost/proto/fusion.hpp:20,
from D:\projects\workspace\boost/boost/proto/core.hpp:21,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/fusion/support/detail/category_of.hpp: In instantiation of 'boost::fusion::detail::fusion_category_of<const boost::phoenix::actor<boost::spirit::attribute<0> > >':
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:44:58: instantiated from 'boost::fusion::extension::category_of_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:66:9: instantiated from 'boost::fusion::traits::category_of<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/fusion/support/category_of.hpp:73:9: instantiated from 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/mpl/if.hpp:67:11: instantiated from 'boost::mpl::if_<boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >, boost::fusion::result_of::key_of<mpl_::arg<1> >, boost::fusion::result_of::value_of<mpl_::arg<1> > >'
D:\projects\workspace\boost/boost/fusion/algorithm/query/find.hpp:45:9: instantiated from 'boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: instantiated from 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp:54:35: instantiated from here
D:\projects\workspace\boost/boost/fusion/support/detail/category_of.hpp:15:38: error: no type named 'category' in 'const struct boost::phoenix::actor<boost::spirit::attribute<0> >'
In file included from D:\projects\workspace\boost/boost/proto/args.hpp:21:0,
from D:\projects\workspace\boost/boost/proto/core.hpp:14,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/mpl/if.hpp: In instantiation of 'boost::mpl::if_<boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >, boost::fusion::result_of::key_of<mpl_::arg<1> >, boost::fusion::result_of::value_of<mpl_::arg<1> > >':
D:\projects\workspace\boost/boost/fusion/algorithm/query/find.hpp:45:9: instantiated from 'boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: instantiated from 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp:54:35: instantiated from here
D:\projects\workspace\boost/boost/mpl/if.hpp:67:11: error: 'value' is not a member of 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
D:\projects\workspace\boost/boost/mpl/if.hpp:70:41: error: 'value' is not a member of 'boost::fusion::traits::is_associative<const boost::phoenix::actor<boost::spirit::attribute<0> > >'
In file included from D:\projects\workspace\boost/boost/fusion/sequence/intrinsic.hpp:20:0,
from D:\projects\workspace\boost/boost/fusion/include/intrinsic.hpp:10,
from D:\projects\workspace\boost/boost/proto/fusion.hpp:22,
from D:\projects\workspace\boost/boost/proto/core.hpp:21,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: In instantiation of 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>':
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp:54:35: instantiated from here
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: error: no type named 'type' in 'struct boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::first>'
..\src\spirit02_test.cpp: In constructor 'G::G()':
..\src\spirit02_test.cpp:54:35: error: no matching function for call to 'at_key(const boost::spirit::_val_type&)'
In file included from D:\projects\workspace\boost/boost/fusion/sequence/intrinsic.hpp:20:0,
from D:\projects\workspace\boost/boost/fusion/include/intrinsic.hpp:10,
from D:\projects\workspace\boost/boost/proto/fusion.hpp:22,
from D:\projects\workspace\boost/boost/proto/core.hpp:21,
from D:\projects\workspace\boost/boost/proto/proto.hpp:12,
from D:\projects\workspace\boost/boost/spirit/home/support/meta_compiler.hpp:19,
from D:\projects\workspace\boost/boost/spirit/home/qi/meta_compiler.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi/action.hpp:14,
from D:\projects\workspace\boost/boost/spirit/home/qi.hpp:14,
from D:\projects\workspace\boost/boost/spirit/include/qi.hpp:16,
from ..\src\spirit02_test.cpp:11:
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: At global scope:
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp: In instantiation of 'boost::fusion::extension::at_key_impl<boost::fusion::non_fusion_tag>::apply<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>':
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:71:9: instantiated from 'boost::fusion::result_of::at_key<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>'
..\src\spirit02_test.cpp:58:36: instantiated from here
D:\projects\workspace\boost/boost/fusion/sequence/intrinsic/at_key.hpp:38:17: error: no type named 'type' in 'struct boost::fusion::result_of::find<const boost::phoenix::actor<boost::spirit::attribute<0> >, keys::second>'
..\src\spirit02_test.cpp: In constructor 'G::G()':
..\src\spirit02_test.cpp:58:36: error: no matching function for call to 'at_key(const boost::spirit::_val_type&)'
If I use a simpler rule (without associativity), everything compiles and works fine, but this solution is somewhat fragile:
// A non-associative solution
//start_rule %= ( ("first" >> qi::int_) ^ ("second" >> qi::int_) );
Why cannot I use at_key in the semantic action? Is there a better way to do an "associative" parse into a non-associative structure?

You need a lazy version of at_key. The patch for this sadly never made it into Spirit (yet):
/*=============================================================================
Copyright (c) 2005-2008 Hartmut Kaiser
Copyright (c) 2005-2007 Joel de Guzman
Copyright (c) 2011 Michael Caisse
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#ifndef PHOENIX_SEQUENCE_AT_KEY_HPP
#define PHOENIX_SEQUENCE_AT_KEY_HPP
#include <boost/fusion/include/at_key.hpp>
#include <boost/spirit/home/phoenix/core/actor.hpp>
#include <boost/spirit/home/phoenix/core/compose.hpp>
#include <boost/type_traits/remove_reference.hpp>
namespace boost { namespace phoenix
{
template <typename Key>
struct at_key_eval
{
template <typename Env, typename Tuple>
struct result
{
typedef typename Tuple::template result<Env>::type tuple;
typedef typename
fusion::result_of::at_key<
typename remove_reference<tuple>::type, Key
>::type
type;
};
template <typename RT, typename Env, typename Tuple>
static RT
eval(Env const& env, Tuple const& t)
{
return fusion::at_key<Key>(t.eval(env));
}
};
template <typename Key, typename Tuple>
inline actor<typename as_composite<at_key_eval<Key>, Tuple>::type>
at_key(Tuple const& tup)
{
return compose<at_key_eval<Key> >(tup);
}
}}
#endif
If you add it, you can use boost::phoenix::at_key:
using boost::phoenix::at_key;
Things will compile and work as expected. The linked patch also modifies boost/spirit/home/phoenix/fusion.hpp to include this new header, of course.

Related

Boost Spirit compilation error "error_invalid_expression"

I am trying to figure out what is wrong with this Boost Spirit code:
#include <iostream>
#include <string>
#include <boost/spirit/include/qi_uint.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
template <typename Iterator>
struct Header
{
struct Type : boost::fusion::vector2<unsigned int, unsigned int>
{
unsigned int getFirstThing() { return boost::fusion::at_c<0>(*this); }
unsigned int getSecondThing() { return boost::fusion::at_c<1>(*this); }
};
};
template<typename Iterator>
struct HeaderParse
: boost::spirit::qi::grammar<Iterator, typename Header<Iterator>::Type() >
{
HeaderParse()
: HeaderParse::base_type(_start)
{
using boost::spirit::qi::uint_parser;
_start = '<'
>> uint_parser<unsigned int, 10, 1, 3>()
>> '>'
>> uint_parser<unsigned int, 10, 1, 3>();
_start.name("HeaderParse");
}
~HeaderParse() = default;
boost::spirit::qi::rule<Iterator, typename Header<Iterator>::Type() > _start;
};
int main()
{
const std::string d1 = "<1>2";
const HeaderParse<std::string::const_iterator> parser;
Header<std::string::const_iterator>::Type header;
std::string::const_iterator begin = d1.begin();
std::string::const_iterator end = d1.end();
assert(boost::spirit::qi::parse(begin, end, parser, header));
return 0;
}
This is the compilation error that I see when I try to compile:
$ make --jobs=8
Scanning dependencies of target testapp
[ 50%] Building CXX object CMakeFiles/testapp.dir/test.cpp.o
In file included from /Users/addy/nw/stub/test.cpp:5:
In file included from /Users/addy/Downloads/boost_1_65_1/boost/spirit/include/qi_grammar.hpp:16:
In file included from /Users/addy/Downloads/boost_1_65_1/boost/spirit/home/qi/nonterminal/grammar.hpp:18:
/Users/addy/Downloads/boost_1_65_1/boost/spirit/home/qi/nonterminal/rule.hpp:177:13: error: static_assert failed "error_invalid_expression"
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
/Users/aclaure/nw/stub/test.cpp:27:16: note: in instantiation of function template specialization 'boost::spirit::qi::rule<std::__1::__wrap_iter<const char *>,
Header<std::__1::__wrap_iter<const char *> >::Type (), boost::spirit::unused_type, boost::spirit::unused_type,
boost::spirit::unused_type>::operator=<boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const
boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right,
boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::lit, boost::fusion::vector<char
const (&)[7]> > >, 0> &, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<const char &>, 0> >, 2> &, const
boost::spirit::qi::uint_parser<unsigned int, 10, 1, 3> &>, 2> &, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<const char &>, 0>
>, 2> &, const boost::spirit::qi::uint_parser<unsigned int, 10, 1, 3> &>, 2> >' requested here
_start =
^
/Users/aclaure/nw/stub/test.cpp:46:52: note: in instantiation of member function 'HeaderParse<std::__1::__wrap_iter<const char *> >::HeaderParse' requested here
const HeaderParse<std::string::const_iterator> parser;
Which leads me to this comment in the Spirit header files:
// Report invalid expression error as early as possible.
// If you got an error_invalid_expression error message here,
// then the expression (expr) is not a valid spirit qi expression.
But the expression I have written seems valid to me. I am not sure what could be wrong with it. Any help is much appreciated!
You're missing a header. I can't say which one but if I just include
#include <boost/spirit/home/qi.hpp>
it compiles.
Live example on Wandbox
N.B.: I couldn't find any “official” statement but I don't think including the individual headers is recommended. At least none of the Qi examples does it.
I guess you only include those headers because you hope to reduce compile-time that way. If you really want to speed things up, consider using X3 instead. This example takes about 1 sec to compile on my machine.
#include <iostream>
#include <string>
#include <tuple>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
namespace Header {
using Type = std::tuple<unsigned int, unsigned int>;
namespace x3 = boost::spirit::x3;
x3::uint_parser<unsigned int, 10, 1, 3> uint_;
x3::rule<class parser, Type> const parser = "parser";
auto const parser_def = '<' >> uint_ >> '>' >> uint_;
BOOST_SPIRIT_DEFINE(parser)
}
int main()
{
const std::string d1 = "<1>2";
Header::Type header;
auto iter = d1.begin();
auto end = d1.end();
bool r = boost::spirit::x3::parse(iter, end, Header::parser, header);
if (!r || iter != end) {
std::cerr << "Parsing failed at " << std::string{iter,end} << "\n";
} else {
std::cout << std::get<0>(header) << " " << std::get<1>(header) << "\n";
}
}
Live example on Wandbox

boost multiprecision + numeric bindings + LAPACK

I'm trying to implement some numeric procedures using the boost multiprecision template library in combination with numeric bindings for a lapack backend.
However, the template resolution doesn't seem to work as intended. I've been able to narrow it down to this minimal example:
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/numeric/bindings/traits/ublas_matrix.hpp>
#include "boost/numeric/bindings/lapack/syev.hpp"
#include "boost/numeric/bindings/lapack/workspace.hpp"
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<100> > SuperFloat;
typedef std::numeric_limits<boost::multiprecision::cpp_dec_float<100> > SuperFloatPrecision;
typedef boost::numeric::ublas::matrix<SuperFloat> Matrix;
typedef boost::numeric::ublas::symmetric_matrix<SuperFloat> MatrixSym;
inline int diagonalize(Matrix& eigenvectors, boost::numeric::ublas::vector<SuperFloat>& eigenvalues) {
int r = boost::numeric::bindings::lapack::syev( 'U', eigenvectors, eigenvalues, boost::numeric::bindings::lapack::minimal_workspace() );
return r;
}
int main(){
std::cout << "hello!" << std::endl;
return 0;
}
which yields this error message:
boost/numeric/bindings/lapack/syev.hpp: In instantiation of ‘int boost::numeric::bindings::lapack::syev(char, A&, W&, boost::numeric::bindings::lapack::minimal_workspace) [with A = boost::numeric::ublas::matrix<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<100u> > >; W = boost::numeric::ublas::vector<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<100u> > >]’:
test.cxx:13:137: required from here
boost/numeric/bindings/lapack/syev.hpp:163:8: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’
BOOST_STATIC_ASSERT( (boost::mpl::or_< boost::is_same< matrix_structure, traits::symmetric_t >
^
In file included from ./boost/numeric/bindings/traits/traits.hpp:18:0,
from ./boost/numeric/bindings/traits/ublas_matrix.hpp:17,
from test.cxx:3:
./boost/numeric/bindings/traits/matrix_traits.hpp: In instantiation of ‘char boost::numeric::bindings::traits::matrix_uplo_tag(SymmM&) [with SymmM = boost::numeric::ublas::matrix<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<100u> > >]’:
boost/numeric/bindings/lapack/syev.hpp:181:47: required from ‘int boost::numeric::bindings::lapack::syev(char, A&, W&, boost::numeric::bindings::lapack::minimal_workspace) [with A = boost::numeric::ublas::matrix<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<100u> > >; W = boost::numeric::ublas::vector<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<100u> > >]’
test.cxx:13:137: required from here
./boost/numeric/bindings/traits/matrix_traits.hpp:141:56: error: no type named ‘uplo_type’ in ‘struct boost::numeric::bindings::traits::matrix_traits<boost::numeric::ublas::matrix<boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<100u> > > >’
typedef typename matrix_traits<SymmM>::uplo_type uplo_t;
Is it at all possible to use lapack as a backend for boost UBLAS templated to multiprecision, or is this a futile endeavour?
Are there any other ways to do, say, an eigenvector decomposition of a ublas multiprecision matrix?

Inner scoped enumeration, hash function and unordered_set data member

I've the following problem of which I cannot find a solution.
Of course, it could be that a solution does not exist at all, but I'd like to have a try on SO before to give up.
First of all, a snippet that compiles with no errors:
#include <unordered_set>
#include <memory>
struct S {
enum class E: unsigned int { FOO = 0, BAR };
};
namespace std
{
template<>
struct hash<S::E> {
using argument_type = S::E;
using underlying_type = std::underlying_type<argument_type>::type;
using result_type = std::size_t;
result_type operator()(argument_type const &s) const noexcept {
const underlying_type us = static_cast<underlying_type>(s);
hash<underlying_type> hfn;
return hfn(us);
}
};
}
int main() {
std::unordered_set<S::E> set;
}
With this code in mind, I found myself with the requirement of having the unordered_set as a data member of S or, at least, a derived class. A possible working solution is to add add the following lines once the std namespace has been closed:
struct D: public S {
std::unordered_set<S::E> set;
};
Another possible solution is maybe (I've not tried it) to use an unscoped enumeration. Anyway, the first attempt I made was to modify the definition of the struct S as it follows:
struct S {
enum class E: unsigned int { FOO = 0, BAR };
std::unordered_set<E> set;
};
This ends in an error because (if I've correctly understood the problem) the unordered_set requires the specialized hash function. Anyway, the latter requires S::E to be at least declared, thus it is not enough to swap the two pieces of code.
Here the first part of the error log (for it's very long):
In file included from /usr/include/c++/5/bits/hashtable.h:35:0,
from /usr/include/c++/5/unordered_set:47,
from main.cpp:1:
/usr/include/c++/5/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> >’:
/usr/include/c++/5/type_traits:137:12: required from ‘struct std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > >’
/usr/include/c++/5/type_traits:148:38: required from ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’
/usr/include/c++/5/bits/unordered_set.h:95:63: required from ‘class std::unordered_set<S::E>’
main.cpp:6:27: required from here
/usr/include/c++/5/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash<S::E>) (const S::E&)’
noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
^
In file included from /usr/include/c++/5/bits/move.h:57:0,
from /usr/include/c++/5/bits/stl_pair.h:59,
from /usr/include/c++/5/utility:70,
from /usr/include/c++/5/unordered_set:38,
from main.cpp:1:
/usr/include/c++/5/type_traits: In instantiation of ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’:
/usr/include/c++/5/bits/unordered_set.h:95:63: required from ‘class std::unordered_set<S::E>’
main.cpp:6:27: required from here
/usr/include/c++/5/type_traits:148:38: error: ‘value’ is not a member of ‘std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > >’
: public integral_constant<bool, !_Pp::value>
^
In file included from /usr/include/c++/5/unordered_set:48:0,
from main.cpp:1:
/usr/include/c++/5/bits/unordered_set.h: In instantiation of ‘class std::unordered_set<S::E>’:
main.cpp:6:27: required from here
/usr/include/c++/5/bits/unordered_set.h:95:63: error: ‘value’ is not a member of ‘std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’
typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable;
^
/usr/include/c++/5/bits/unordered_set.h:102:45: error: ‘value’ is not a member of ‘std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’
typedef typename _Hashtable::key_type key_type;
Usually, in such a case, I can solve with something like a forward declaration, as the one in the example below:
struct B;
struct A { B *link; };
struct B { A *link; };
Unfortunately, I've not been able to do something similar with the enum embedded in a struct and that's why I started this question. Is it possible to solve it, thus avoid to define the derived class D, or deriving is the only viable solution in this case?
You can't forward declare a nested enum, see this answer.
You can do as ForEveR explained, or you can have your generic enum_hash template regardless of std namespace and use it in your data structure, since you are not forced to use std::hash as the hashing function, eg:
template<typename T>
struct enum_hash {
using argument_type = T;
using underlying_type = typename std::underlying_type<argument_type>::type;
using result_type = std::size_t;
result_type operator()(argument_type const &s) const noexcept {
const underlying_type us = static_cast<underlying_type>(s);
std::hash<underlying_type> hfn;
return hfn(us);
}
static_assert(std::is_enum<T>::value, "T must be an enum!");
};
struct S {
enum class E: unsigned int { FOO = 0, BAR };
std::unordered_set<S::E, enum_hash<S::E>> set;
};
You can just write specialization of hash for all enums and then all would work fine.
namespace std {
template<class E>class hash {
using sfinae = typename std::enable_if<std::is_enum<E>::value, E>::type;
public:
size_t operator()(const E&e) const {
return std::hash<typename std::underlying_type<E>::type>()(e);
}
};
};

"<class name> does not provide a call operator" error when trying to wrap function return value

I'm trying to write a function that will take a functor as an argument, invoke the functor and then return its return value wrapped in a boost::shared_ptr.
The following refuses to compile and I'm all out of ideas. I get "std::vector< std::string > does not provide a call operator" (roughly). I'm using Clang 3.1 on Mac OS X.
template< typename T >
boost::shared_ptr< T > ReturnValueAsShared(
boost::function< T() > func )
{
return boost::make_shared< T >( func() );
}
This is the context in which I'm trying to use it:
make_shared< packaged_task< boost::shared_ptr< std::vector< std::string > > > >(
bind( ReturnValueAsShared< std::vector< std::string > >,
bind( [a function that returns a std::vector< std::string >] ) ) );
EDIT: Here's a complete self-contained test case. This code fails to compile with the same error, and for the life of me I can't see what's wrong:
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <string>
#include <vector>
std::vector< std::string > foo( std::string a )
{
std::vector< std::string > vec;
vec.push_back( a );
return vec;
}
template< typename T >
boost::shared_ptr< T > ReturnValueAsShared(
boost::function< T() > func )
{
return boost::make_shared< T >( func() );
}
int main()
{
auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
boost::bind( foo, std::string("a") ) );
f();
} // main
And here's the error output:
In file included from testcase.cpp:3:
In file included from /usr/local/include/boost/function.hpp:64:
In file included from /usr/local/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:47:
In file included from /usr/local/include/boost/function/detail/function_iterate.hpp:14:
In file included from /usr/local/include/boost/function/detail/maybe_include.hpp:13:
/usr/local/include/boost/function/function_template.hpp:132:18: error: type 'std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >' does not provide a call operator
return (*f)(BOOST_FUNCTION_ARGS);
^~~~
/usr/local/include/boost/function/function_template.hpp:907:53: note: in instantiation of member function 'boost::detail::function::function_obj_invoker0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >::invoke' requested here
{ { &manager_type::manage }, &invoker_type::invoke };
^
/usr/local/include/boost/function/function_template.hpp:722:13: note: in instantiation of function template specialization 'boost::function0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >::assign_to<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >' requested here
this->assign_to(f);
^
/usr/local/include/boost/function/function_template.hpp:1042:5: note: in instantiation of function template specialization 'boost::function0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >::function0<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >' requested here
base_type(f)
^
/usr/local/include/boost/bind/bind.hpp:243:43: note: in instantiation of function template specialization 'boost::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > ()>::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >' requested here
return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_]);
^
/usr/local/include/boost/bind/bind_template.hpp:20:27: note: in instantiation of function template specialization 'boost::_bi::list1<boost::_bi::bind_t<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > (*)(std::basic_string<char>), boost::_bi::list1<boost::_bi::value<std::basic_string<char> > > > >::operator()<boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >, boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > (*)(boost::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > ()>), boost::_bi::list0>' requested here
BOOST_BIND_RETURN l_(type<result_type>(), f_, a, 0);
^
testcase.cpp:27:4: note: in instantiation of member function 'boost::_bi::bind_t<boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >, boost::shared_ptr<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > (*)(boost::function<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > ()>), boost::_bi::list1<boost::_bi::bind_t<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > (*)(std::basic_string<char>), boost::_bi::list1<boost::_bi::value<std::basic_string<char> > > > > >::operator()' requested here
f();
^
1 error generated.
Here are some more clues. The following code compiles just fine, but that doesn't help me since this is not the code that I want :)
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <string>
#include <vector>
std::vector< std::string > foo()
{
std::vector< std::string > vec;
return vec;
}
template< typename T >
boost::shared_ptr< T > ReturnValueAsShared(
boost::function< T() > func )
{
return boost::make_shared< T >( func() );
}
int main()
{
auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
foo );
f();
} // main
boost::protect is the way to go:
int main()
{
auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
boost::protect(boost::bind( foo, std::string("a") ) ) );
f();
} // main
This is as clean as it can get.
Some constructions (such as bind) return intermediate "expression" types which you don't actually want to capture on the nose. In that case, you mustn't capture the type via auto, and you may need to specify explicit conversions, since otherwise there isn't a unique, single user-defined conversion chain. In your case, add the explicit conversion from the bind expression to function:
typedef std::vector<std::string> G;
auto f = boost::bind(ReturnValueAsShared<G>,
static_cast<boost::function<G()>(boost::bind(foo, std::string("a")))
);
(This itself doesn't actually work for me, but it does work if you use the corresponding std construc­tions.)
Complete rewrite, original answer was incorrect.
Error analysis
As I didn't know at first what was going wrong here, I did some analysis. I'm keeping it for future reference; see the solution below for how to avoid the problem.
bind.hpp does this:
return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_]);
which in my opinion translates like this:
unwrapper<F>::unwrap(f, 0) = ReturnValueAsShared< std::vector< std::string > >
base_type::a1_ = boost::bind( foo, std::string("a") )
So what you would expect this code to do is pass the argument to the function, just the way it is. But for this to work, the expression a[base_type::a1_] would have to be of type boots:_bi::value<T>, whereas it is of the unwrapped type boost::_bi::bind_t. So instead of the functor being passed as the argument, a special overloaded version gets called:
namespace boost { namespace _bi { class list0 {
…
template<class R, class F, class L>
typename result_traits<R, F>::type
operator[] (bind_t<R, F, L> & b) const {
return b.eval(*this);
}
…
} } }
This will evaluate the nullary function, instead of passing it on. So instead of an object returning a vector, the argument now is a vecotr. Subsequent steps will attempt to convert that to a boost::function and fail.
Canonical solution
Edited yet again:
It looks like this special handling of nested binds is intended as a feature. Talking on #boost with users Zao and heller, I now know that there is a protect function to counter these effects. So the canonical solution to this problem appears to be the following:
…
#include <boost/bind/protect.hpp>
…
auto f = boost::bind( ReturnValueAsShared< std::vector< std::string > >,
boost::protect ( boost::bind( foo, std::string("a") ) ) );
…

Vector of vectors of T in template<T> class

Why this code does not compile (Cygwin)?
#include <vector>
template <class Ttile>
class Tilemap
{
typedef std::vector< Ttile > TtileRow;
typedef std::vector< TtileRow > TtileMap;
typedef TtileMap::iterator TtileMapIterator; // error here
};
error: type std::vector<std::vector<Ttile, std::allocator<_CharT> >, std::allocator<std::vector<Ttile, std::allocator<_CharT> > > >' is not derived from typeTilemap'
Because the TtileMap::iterator is not known to be a type yet. Add the typename keyword to fix it
typedef typename TtileMap::iterator TtileMapIterator;