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
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.
来源:https://stackoverflow.com/questions/8305863/boost-variant-boost-mpl-how-to-append-types