[typeof][spirit][msvc gurus] is it possible to work around this bug??

Hi List, The code below fails to compile with MSVC8 when the macro MAKE_THINGS_FAIL is defined. I hope the code reads well enough to communicate the problem and why it would be quite hot to get it fixed ;-). Thanks a lot for your help, Tobias #include <boost/spirit/core.hpp> #include <boost/typeof/typeof.hpp> #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() BOOST_TYPEOF_REGISTER_TYPE(boost::spirit::anychar_parser) BOOST_TYPEOF_REGISTER_TEMPLATE(boost::spirit::action, 2) BOOST_TYPEOF_REGISTER_TEMPLATE(boost::spirit::positive, 1) #define an_expression +anychar_p[ a_placeholder ] typedef void (* fptr)(char const * from, char const * to); void echo(char const * from, char const * to) { // [...] } #ifndef MAKE_THINGS_FAIL using boost::spirit::anychar_p; class a_rule_parser : boost::spirit::parser<a_rule_parser> { fptr a_placeholder; struct __rule { // hide the placeholder member variable of the outer class with a static // variable of the same type static fptr & a_placeholder; typedef BOOST_TYPEOF( an_expression ) type; }; __rule::type __expr; public: a_rule_parser(fptr placeholder) : a_placeholder( placeholder ) , __expr( an_expression ) { } // [...] (it's stripped down code to show a bug) }; int main() { a_rule_parser x(& echo); return 0; } // so far, so good... #else // ...but the same code in templated form makes msvc8 do strange things // using boost::spirit::anychar_p; using namespace boost::spirit; // ADL doesn't seem to work, either but I could live with this problem ;-) template<typename T> class a_rule_parser_template : boost::spirit::parser< a_rule_parser_template<T> > { T a_placeholder; struct __rule { // hide the placeholder member variable of the outer class with a static // variable of the same type static T & a_placeholder; typedef BOOST_TYPEOF_TPL( an_expression ) type; }; typename __rule::type __expr; public: a_rule_parser_template(T const & placeholder) : a_placeholder( placeholder ) , __expr( an_expression ) { } // [...] (it's stripped down code to show a bug) }; int main() { a_rule_parser_template<fptr> x(& echo); return 0; } #endif

template<typename T> class a_rule_parser_template : boost::spirit::parser< a_rule_parser_template<T> > { T a_placeholder;
struct __rule { // hide the placeholder member variable of the outer class with a static // variable of the same type static T & a_placeholder;
typedef BOOST_TYPEOF_TPL( an_expression ) type; Line 77 ^^ Typeof acts like a black hole in this context; the "laws of C++ physics" seem not to apply any longer. There should be absolutely no reason for deduction to fail
Forgot something... Tobias Schwinger wrote: like this: test.cpp(77) : error C2784: 'boost::spirit::positive<S> boost::spirit::operator +(const boost::spirit::parser<DerivedT> &)' : could not deduce template argument for 'const boost::spirit::parser<DerivedT> &' from 'T' e:\Libs\Boost\MainCVS2\boost/spirit/core/composite/positive.hpp(93) : see declaration of 'boost::spirit::operator +' test.cpp(72) : see reference to class template instantiation 'a_rule_parser_template<T>::__rule' being compiled test.cpp(89) : see reference to class template instantiation 'a_rule_parser_template<T>' being compiled test.cpp(77) : error C2675: unary '+' : 'T' does not define this operator or a conversion to a type acceptable to the predefined operator test.cpp(77) : error C2784: 'boost::spirit::positive<S> boost::spirit::operator +(const boost::spirit::parser<DerivedT> &)' : could not deduce template argument for 'const boost::spirit::parser<DerivedT> &' from 'T' e:\Libs\Boost\MainCVS2\boost/spirit/core/composite/positive.hpp(93) : see declaration of 'boost::spirit::operator +' test.cpp(77) : error C2675: unary '+' : 'T' does not define this operator or a conversion to a type acceptable to the predefined operator test.cpp(77) : error C2784: 'boost::spirit::positive<S> boost::spirit::operator +(const boost::spirit::parser<DerivedT> &)' : could not deduce template argument for 'const boost::spirit::parser<DerivedT> &' from 'T' e:\Libs\Boost\MainCVS2\boost/spirit/core/composite/positive.hpp(93) : see declaration of 'boost::spirit::operator +' [...] last two messages repeat several times -- Tobias

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Typeof acts like a black hole in this context; the "laws of C++ physics" seem not to apply any longer. There should be absolutely no reason for deduction to fail like this:
test.cpp(77) : error C2784: 'boost::spirit::positive<S> boost::spirit::operator +(const boost::spirit::parser<DerivedT> &)' : could not deduce template argument for 'const boost::spirit::parser<DerivedT> &' from 'T'
What's T? There seem to be a number of contexts when some types can't be bound to const T&. For example VC71 can't do it from inside the template when T is a function (see currently failig typeof test). Regards, Arkadiy

Arkadiy Vertleyb wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
test.cpp(77) : error C2784: 'boost::spirit::positive<S> boost::spirit::operator +(const boost::spirit::parser<DerivedT> &)' : could not deduce template argument for 'const boost::spirit::parser<DerivedT> &' from 'T'
What's T?
/I/ don't know what T really is (MSVC won't tell me) ;-). T /should/ be: action<anychar_parser, void(*)(char const *, char const *)> where template<class P, typename A> class action<P,A> is derived from parser< action<P,A> > however.
There seem to be a number of contexts when some types can't be bound to const T&. For example VC71 can't do it from inside the template when T is a function (see currently failig typeof test).
I had a look at the 'function_ptr_from_tpl' test and instantly changed my code to use a functor instead of a function pointer -- with best hopes but a bad feeling because I thought I'd tried it before... Most unfortunately the function pointer is not the problem, here. Same problem, except that T should now be: action<anychar_parser, functor> ...and MSVC still won't tell us ;-). Thanks anyway, Tobias #include <boost/spirit/core.hpp> #include <boost/typeof/typeof.hpp> #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() BOOST_TYPEOF_REGISTER_TYPE(boost::spirit::anychar_parser) BOOST_TYPEOF_REGISTER_TEMPLATE(boost::spirit::action, 2) BOOST_TYPEOF_REGISTER_TEMPLATE(boost::spirit::positive, 1) #define an_expression +anychar_p[ a_placeholder ] struct functor { void operator()(char const * from, char const * to) const { // [...] } }; BOOST_TYPEOF_REGISTER_TYPE(functor) #ifndef MAKE_THINGS_FAIL using boost::spirit::anychar_p; class a_rule_parser : boost::spirit::parser<a_rule_parser> { functor a_placeholder; struct __rule { // hide the placeholder member variable of the outer class with a static // variable of the same type static functor & a_placeholder; typedef BOOST_TYPEOF( an_expression ) type; }; __rule::type __expr; public: a_rule_parser(functor placeholder) : a_placeholder( placeholder ) , __expr( an_expression ) { } // [...] (it's stripped down code to show a bug) }; int main() { functor f; a_rule_parser x(f); return 0; } // so far, so good... #else // ...but the same code in templated form makes msvc8 do strange things // using boost::spirit::anychar_p; using namespace boost::spirit; // ADL doesn't seem to work, either but I could live with this problem ;-) template<typename T> class a_rule_parser_template : boost::spirit::parser< a_rule_parser_template<T> > { T a_placeholder; struct __rule { // hide the placeholder member variable of the outer class with a static // variable of the same type static T & a_placeholder; typedef BOOST_TYPEOF_TPL( an_expression ) type; }; typename __rule::type __expr; public: a_rule_parser_template(T const & placeholder) : a_placeholder( placeholder ) , __expr( an_expression ) { } // [...] (it's stripped down code to show a bug) }; int main() { functor f; a_rule_parser_template<functor> x(f); return 0; } #endif

"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Most unfortunately the function pointer is not the problem, here. Same problem, except that T should now be:
action<anychar_parser, functor>
...and MSVC still won't tell us ;-).
Can you take the expression whose typeof you are trying to take, and just pass it into: template<class T> void foo(const T&) {} If it still fails, binding is the problem. We will not solve the problem this way, but we'll at least classify it... Regards, Arkadiy

Arkadiy Vertleyb wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
Most unfortunately the function pointer is not the problem, here. Same problem, except that T should now be:
action<anychar_parser, functor>
...and MSVC still won't tell us ;-).
Can you take the expression whose typeof you are trying to take, and just pass it into:
template<class T> void foo(const T&) {}
I can. I can also use a function template like template<typename T> int eat(T const &) { return 0; } and #define an_expression eat(anychar_p[ a_placeholder ]) // note: eat(T const &) in place of of the operator+(parser<D> const &) and it works within Typeof. Even better (and now things really get weird): #define an_expression anychar_p[ a_placeholder ] >> anychar_p // note: don't forget to register boost::spirit::sequence<class,class> // when trying this one works. Looking at definition of operator>> in boost/spirit/core/composite/sequence.hpp we see the same deduction. The only differences: it's a binary operator and heavily overloaded (for one parser argument and the other argument being char, wchar_t, char const *, wchar_t const *). So I added a function like this template<typename U, typename V> int whattheheck(boost::spirit::parser<U> const &, boost::spirit::parser<V> const &) { return 0; } #define an_expression whattheheck(anychar_p[ a_placeholder ],anychar_p) and get an error. Now when I add an overload like this: struct surprise { }; template<typename U> int whattheheck(surprise, boost::spirit::parser<U> const &) { return 0; } things work again.
If it still fails, binding is the problem. We will not solve the problem this way, but we'll at least classify it...
Well, I just found a workaround while just replying (the "cardboard programmer" [ http://tinyurl.com/9xcf7 ] effect, I guess). The workaround isn't too pretty (especially because I still don't really understand it) but still: namespace boost { namespace spirit { struct msvc_workaround { }; int operator+(msvc_workaround) { return 0; } } } Thanks, Tobias

Tobias Schwinger wrote:
namespace boost { namespace spirit {
struct msvc_workaround { }; int operator+(msvc_workaround) { return 0; }
} }
For the protocol: Better (Spirit-specific) solution: add overloads for character & string literals (they should be there at least for the sake of completeness).

Tobias Schwinger wrote:
Tobias Schwinger wrote:
namespace boost { namespace spirit {
struct msvc_workaround { }; int operator+(msvc_workaround) { return 0; }
} }
VVVV
For the protocol:
Better (Spirit-specific) solution: add overloads for character & string literals (they should be there at least for the sake of completeness).
^^^^ nonsense (at least in this case): an arithmetic operator can't be overloaded for an arithmetic type...

Tobias Schwinger <tschwinger@neoscientists.org> writes:
Arkadiy Vertleyb wrote:
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote
test.cpp(77) : error C2784: 'boost::spirit::positive<S> boost::spirit::operator +(const boost::spirit::parser<DerivedT> &)' : could not deduce template argument for 'const boost::spirit::parser<DerivedT> &' from 'T'
What's T?
/I/ don't know what T really is (MSVC won't tell me) ;-).
have you tried instantiating an un-defined template on T? template <class T> struct unknown; then instantiate unknown<T> or instantiate boost::mpl::print<T> if this could happen any number of times, to avoid stopping compilation. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Tobias Schwinger <tschwinger@neoscientists.org> writes:
Arkadiy Vertleyb wrote:
What's T?
/I/ don't know what T really is (MSVC won't tell me) ;-).
have you tried instantiating an un-defined template on T?
The only problem left is: if add code to deduce the type (to instantiate a template on it) I still won't know what the type was in the context the compiler failed to deduce from for absolutely non-obvious reasons ;-).
template <class T> struct unknown;
then instantiate
unknown<T>
or instantiate boost::mpl::print<T> if this could happen any number of times, to avoid stopping compilation.
Interesting! Never noticed mpl::print before... It must be either new or undocumented... Thanks, Tobias
participants (3)
-
Arkadiy Vertleyb
-
David Abrahams
-
Tobias Schwinger