[fusion] Possible BUG: invoke does not work with zero arguments

Hi all, following code fails to compile: #include <boost/fusion/functional/invocation/invoke.hpp> #include <boost/fusion/include/make_vector.hpp> namespace fusion = boost::fusion; struct foo_t { int operator()() { return 1; } int operator()(int) { return 2; } template<typename>struct result { typedef int type; }; }; int main(int, char**) { foo_t foo; assert( fusion::invoke(foo, fusion::make_vector(3)) == 2 ); assert( fusion::invoke(foo, fusion::make_vector()) == 1 ); // COMPILE ERROR HERE ! } Boost is released 1.35, compiler gcc 4.2 Thanks for your help Marco

Marco Costalba wrote:
Hi all,
following code fails to compile:
It's not a bug: boost::result_of (which is used by fusion::invoke) needs to be specialized for nullary function objects. Alternatively you can use typedef int result_type; for the example case you posted. Regards, Tobias

On Tue, Jun 3, 2008 at 5:40 AM, Marco Costalba <mcostalba@gmail.com> wrote:
Hi all,
following code fails to compile:
#include <boost/fusion/functional/invocation/invoke.hpp> #include <boost/fusion/include/make_vector.hpp>
namespace fusion = boost::fusion;
struct foo_t { int operator()() { return 1; } int operator()(int) { return 2; }
template<typename>struct result { typedef int type; }; };
int main(int, char**) { foo_t foo;
assert( fusion::invoke(foo, fusion::make_vector(3)) == 2 );
assert( fusion::invoke(foo, fusion::make_vector()) == 1 ); // COMPILE ERROR HERE ! }
Boost is released 1.35, compiler gcc 4.2
This is actual a problem with the legacy/pre-C++0x result_of heuristic. If you use boost trunk and gcc 4.3 with -std=c++0x, your example will compile without error due to the new decltype-based result_of. For C++98, the only solution is to specialize result_of for nullary calls of your functor. namespace boost { template<> struct result_of<foo_t()> { typedef int type; }; } The reason result_of couldn't deduce argument dependent return types for nullary invocations in C++98 is that according to the heuristic only the result_type member is checked for nullary calls, and for non-nullary calls if the result_type is present, result<> is never checked. So, you can't have both. Daniel Walker

On Tue, Jun 3, 2008 at 5:19 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
The reason result_of couldn't deduce argument dependent return types for nullary invocations in C++98 is that according to the heuristic only the result_type member is checked for nullary calls, and for non-nullary calls if the result_type is present, result<> is never checked. So, you can't have both.
Thanks Daniel and Tobias for you explanation. Now this point it's clear to me. Here it is another undocumented behaviour of boost::fusion. Did you know that dereferencing a fusion iterator to a mpl sequence causes a duplication of the pointed object? Following the test code: static int cnt = 0; struct Test { Test() { cnt++; } }; using namespace boost::fusion; int main(int, char**) { typedef boost::mpl::vector<Test,Test> Mpl_vec; Mpl_vec mpl_vec; result_of::begin<Mpl_vec>::type iter = begin(mpl_vec); cout << cnt << endl; // prints 0 deref(iter); cout << cnt << endl; // prints 1 *iter; cout << cnt << endl; // prints 2 return 0; } I found this while traversing a sequence with fusion::for_each because code started to create a lot of copies of the sequence elements, indeed the whole sequence is duplicated each time it's traversed with fusion::for_each !! Is this foreseen or it's a bug. Thanks Marco BTW dereferencing an iterator to a fusion sequence does not show this behaviour and does not copy anything.

Marco Costalba wrote:
Here it is another undocumented behaviour of boost::fusion.
Did you know that dereferencing a fusion iterator to a mpl sequence causes a duplication of the pointed object?
Following the test code:
static int cnt = 0;
struct Test { Test() { cnt++; } };
using namespace boost::fusion;
int main(int, char**) { typedef boost::mpl::vector<Test,Test> Mpl_vec;
Mpl_vec mpl_vec;
result_of::begin<Mpl_vec>::type iter = begin(mpl_vec);
cout << cnt << endl; // prints 0
deref(iter);
cout << cnt << endl; // prints 1
*iter;
cout << cnt << endl; // prints 2
return 0; }
I found this while traversing a sequence with fusion::for_each because code started to create a lot of copies of the sequence elements, indeed the whole sequence is duplicated each time it's traversed with fusion::for_each !!
Is this foreseen or it's a bug.
It's a feature ;-)... Here's why: mpl sequences do not have storage. So how do you get a value? You get it whenever you dereference an iterator. It's computed on the fly, so to speak. It's generated. If that's not what you want, first make a fusion /container/ from the mpl sequence. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
participants (4)
-
Daniel Walker
-
Joel de Guzman
-
Marco Costalba
-
Tobias Schwinger