Boost.Variant、Boost.MPL:如何追加类型?
我看着这个基于 boost.Any 的代码,不禁想知道我们是否可以使用Boost.Variant 代替。我想知道这样的 API 是否可行:
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;
}
这意味着最后编译器必须编译如下内容:
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;
}
更新:
我尝试过什么(基于此 变体文档 和这个 MPL 演示 和 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;
}
但它无法编译,并出现 2 个相同的错误:
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
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是不可能的。
operator[]
是运行时的事情,而类型是编译时的事情。那么编译器应该编译以下内容吗?编译器如何知道第二次调用
some_condition()
是否给出与之前相同的结果?或者中间的代码是否修改了str
的值?那么以下情况如何:
编译器如何知道在调用时
funcs
是否包含将"voidFunc"
映射到不带参数的函数的条目?如果用一个值调用它一次,又用一个不调用值调用一次,会发生什么情况?根据您实际想要实现的目标,可能有一种方法可以通过模板和 constexpr 函数来实现。但请注意,运行时发生的任何事情都不会影响代码是否编译,原因很简单,代码在编译之前无法运行。
It is not possible.
operator[]
is a run-time thing, while types are a compile-time thing. So should the compiler compile the following?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 ofstr
?What about the following:
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.