1

Lyrics:

I try to implement a task pool over MPI. So I need some kind of RPC but one that would work between different parts of my program, meaning processor A wants processor B to call function C with argument D. We can not pass pointers to functions between processes like we do with threads, so we need some wrapper container to hold our function pointers at each process instance. All inside one source file\one program... So I started wondering about How to store functional objects with different signature in a container. My API Idea back then was wrong - it is better to define all functions in function pool at that pool construction (at least it shall be much easier to implement). But while implementing I faced next trouble:

Problem:

Such simple code (function_types, mpl::vector, variant):

#include <boost/function_types/function_type.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/variant.hpp>

#include <iostream>
#include <string>

template <class T>
int append(T val)
{
    std::cout << "hello";
    return 0;
}

int main()
{
    boost::variant<boost::function_types::function_type< boost::mpl::vector<int,int> >::type , boost::function_types::function_type< boost::mpl::vector<int,std::string> >::type  > a;
    return 0;
} 

Will not compile falling with:

Error   1   error C2066: cast to function type is illegal   c:\program files\boost\include\boost\variant\variant.hpp    1231    1

And looking at source we see:

this code block:

variant()
{
    // NOTE TO USER :
    // Compile error from here indicates that the first bound
    // type is not default-constructible, and so variant cannot
    // support its own default-construction.
    //
    new( storage_.address() ) internal_T0();
    indicate_which(0); // zero is the index of the first bounded type
}

So I wonder: How to get around this error?

Also I tried:

#include <boost/function_types/function_type.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>

#include <iostream>
#include <string>

template <class T>
int append(T val)
{
    std::cout << "hello";
    return 1;
}

int main()
{
    boost::variant< boost::function<int (std::string) >, boost::function<int (int) > > a;
    a= &append<int>;

    return 0;
}

Which fails with:

Error   1   error C2668: 'boost::detail::variant::make_initializer_node::apply<BaseIndexPair,Iterator>::initializer_node::initialize' : ambiguous call to overloaded function   c:\program files\boost\include\boost\variant\variant.hpp    1330

Any Ideas on how to make boost.variant hold functions?

Of course we can play with shared pointers to functors like so:

#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>

#include <iostream>
#include <string>

template <class in, class out>
struct s_append
{
    out operator()(in val) {
        std::cout << "hello";
        return out();
    }
};

int main()
{
    boost::variant<boost::shared_ptr<s_append<int, int> >, boost::shared_ptr< s_append<std::string, int> > > a;
    boost::shared_ptr<s_append<int, int> > b(new s_append<int, int> );
    a=b;
    return 0;
}

and it would compile but resulting API sucks - you have to 1) create functors for all functions you want to use (meaning limit there use of current process scope); 2) use shared_pointers and so I don't really even get how to call functions nested that way (simple first guess (*a)(22); just won't compile =( and API starts to be as bad as we would have using Boost.Any).

Community
  • 1
  • 1
myWallJSON
  • 9,110
  • 22
  • 78
  • 149
  • 1
    I don't quite understand the question in connection to the source code but I think what you really want is some interprocess communication. I suggest you have a look at Boost.Interprocess http://www.boost.org/doc/libs/1_48_0/doc/html/interprocess.html – mantler Nov 29 '11 at 20:47
  • @manler: Interprocess is across one machine... MPI is across many=) – myWallJSON Nov 29 '11 at 20:57
  • yeah, use `boost:bind()` – karlphillip Nov 29 '11 at 20:59
  • @myWallJSON Aha! I was wondering what you mean when you mentioned RPC and MPI but in the source code you are using mpl(meta programming). So what does the source code have to do with the question? Why are you using mpl vector in the variant? – mantler Nov 29 '11 at 21:04
  • @manler: generally I want to do [this](http://stackoverflow.com/a/8304873/1056328) but in a way like [this](http://stackoverflow.com/questions/8305863/boost-variant-boost-mpl-how-to-append-types) and so my inter cluster task pool based on MPI would have nice API. – myWallJSON Nov 29 '11 at 22:14
  • @karlphillip: Boost.Bind, it is grate but how to deal with return types, and how to deal with the fact that I want to bind functions say once and than call them as many times as I need with difrent data (which is not what boost.bind is for at all)? – myWallJSON Nov 29 '11 at 22:17
  • @myWallJSON: you can call the result of boost::bind() many times with different arguments--in fact this is often done, but not with *all* the arguments of the function being different. It looks like `boost::bind(func, arg1, _1, _2)` when you want to call func(arg1, x, y) by calling result(x, y) (see "currying" on wikipedia). – John Zwinck Nov 30 '11 at 01:54

1 Answers1

0

Try inserting a dummy type as the first argument of the variant. As the comment you found explains, only the first type in the variant is used for the variant's own default constructor. You could use an empty struct type for this (struct NoFunction {};).

That said, you may have been onto something with the idea to use boost::functions as the types in the variant...they are default-constructible at least. I'm not sure what the other error you had from that approach was caused by, but just wanted to let you know you could pursue that angle more if you can't use the dummy-type workaround I mentioned.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436