0

I look at this grate code based on boost.Any and cant help but wonder if we could use Boost.Variant instead. I wonder if such API would be possible:

void voidFunc()
{
    std::cout << "void called" << std::endl;
}

int stringFunc(std::string str)
{
    std::cout << str << std::endl;
    return 0;
}

int main()
{
    some_map_like_type<std::string, boost::variant> funcs;
    funcs.insert<void , void >("voidFunc", &voidFunc)); // now our variant vould contain something like boost::function<void, void>
    funcs.insert<int , std::string>("stringFunc", &stringFunc)); // and now we added to our variant a new type: boost::function<int , std::string>
    funcs.insert<void , void >("voidFunc2", &voidFunc)); // and now our variant should not change because it already contains boost::function<void, void> type


    // And here when all the fun part is:
    funcs["voidFunc"](); // compiles
    funcs["stringFunc"]("hello"); // compiles
    funcs["stringFunc"](some_not_std_string_class); // does not compile.
    return 0;
}

That means that at the end compiler would have to compile something like:

void voidFunc()
{
    std::cout << "void called" << std::endl;
}

int stringFunc(std::string str)
{
    std::cout << str << std::endl;
    return 0;
}

int main()
{
    some_map_like_type<std::string, boost::variant< boost::function<void , void>, boost::function<int , std::string> > > funcs;
    funcs.insert<void , void >("voidFunc", &voidFunc)); // now our variant vould contain something like boost::function<void, void>
    funcs.insert<int , std::string>("stringFunc", &stringFunc)); // and now we added to our variant a new type: boost::function<int , std::string>
    funcs.insert<void , void >("voidFunc2", &voidFunc)); // and now our variant should not change because it already contains boost::function<void, void> type


    // And here when all the fun part is:
    funcs["voidFunc"](); // compiles
    funcs["stringFunc"]("hello"); // compiles
    funcs["stringFunc"](some_not_std_string_class); // here it would give error and would not compile
    return 0;
}

Update:

What have I tried (based on this Variant docs and this MPL demos and docs):

#include <boost/static_assert.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/placeholders.hpp>

#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <vector>

class sudo_science
{
public:
    typedef  boost::mpl::vector_c<int> types_vector1;

    typedef boost::make_recursive_variant< types_vector1 >::type recursive_variant_t;

    std::vector< recursive_variant_t > variant_seq;

    template <typename T>
    void append(T val)
    {
        typedef  boost::mpl::push_back<types_vector1,T>::type types_vector1;
        variant_seq.push_back(val);
        return;
    }

    std::vector< recursive_variant_t > give_me_end_variant()
     {
         return variant_seq;
     }
};

int main()
{
    sudo_science a;
    a.append<float>(1.0);
    a.append<std::string>("Stack and Boost");

    //sorry for C++11
    auto varint = a.give_me_end_variant();

    return 0;
}

But it fails to compile with 2 same errors:

Error   1   error C2665: 'boost::detail::variant::make_initializer_node::apply<BaseIndexPair,Iterator>::initializer_node::initialize' : none of the 2 overloads could convert all the argument types    c:\program files\boost\include\boost\variant\variant.hpp    1330    1
Community
  • 1
  • 1
myWallJSON
  • 9,110
  • 22
  • 78
  • 149
  • 2
    What are you trying to accomplish? There's probably a much easier way. – GManNickG Nov 29 '11 at 04:34
  • The only diffculty is functions that differ in return type only. With overloading I can trivially resolve `funcs["stringFunc"]("hello");` and even figure out that `funcs["stringFunc"](some_not_std_string_class);` should not compile. But add a `function` to the variant, and it falls apart. – MSalters Nov 29 '11 at 12:42
  • @MSalters: described issue (tall me if its same you ran into?) [here](http://stackoverflow.com/questions/8317375/boostvariant-and-function-types-in-it-how-to-resolve-error-c2066-cast-to-fun) – myWallJSON Nov 29 '11 at 20:37
  • @GMan: Described problem/ what I try to accomplish [here](http://stackoverflow.com/questions/8317375/boostvariant-and-function-types-in-it-how-to-resolve-error-c2066-cast-to-fun) – myWallJSON Nov 29 '11 at 20:38

1 Answers1

-1

It is not possible. operator[] is a run-time thing, while types are a compile-time thing. So should the compiler compile the following?

char const* str;
if (some_condition())
  str = "voidFunc";
else
  str = "stringFunc";
// ... some more code
if (some_condition())
  funcs[str]();
else
  funcs[str](str);

How is the compiler supposed to know whether the second call to some_condition() gives the same result as before? Or whether the code in between modified the value of str?

What about the following:

void call(some_map_like_type<std::string, boost::variant> const& funcs)
{
  funcs["voidFunc"]();
}

How is the compiler supposed to know whether at call time funcs contains an entry mapping "voidFunc"to a function with no arguments? And what should happen if it is called once on with a value that does, and once with a value which doesn't?

Depending on what you actually want to achieve, there might be a way to get it with templates and constexpr functions. However note that nothing which happens at runtime can affect whether the code compiles, for the simple reason that the code cannot be run before it is compiled.

celtschk
  • 19,311
  • 3
  • 39
  • 64
  • updated q... I hope this can be done with something like [this](http://stackoverflow.com/questions/8306743/c-can-we-collect-types) – myWallJSON Nov 29 '11 at 08:12
  • Wrong answer, it's possible: the argument types are known. – MSalters Nov 29 '11 at 12:19
  • @MSalters: No, the argument types to be accepted at compile time are *not* known. They are specified by calls to `funcs.insert<>`, and depend on which calls to this function have been done. – celtschk Nov 29 '11 at 15:46
  • boost::variant has a finite number of contained types; `funcs.insert<>` cannot influence that set. You will get a compile-time error when you try to assign a variable of the wrong type to that variant. – MSalters Nov 30 '11 at 19:37
  • @MSalters: But if you read the question, that's exactly what myWallJSON asks for. And to that I answered. – celtschk Nov 30 '11 at 21:10