我有一个地图 std::map
,它来自 boost::program_options
包。现在我想打印该地图的内容:
for(po::variables_map::const_iterator it = vm.begin(); it != vm.end(); ++it) {
std::cerr << it->first << ": " << it->second << std::endl;
}
不幸的是,这是不可能的,因为 boost::any
没有定义 operator<<
。
打印该地图最简单的方法是什么?
我可以为任何自动尝试将每个 any
转换为 int、然后是 double、然后是字符串等定义自己的输出运算符,每次都会忽略错误并尝试进行转换,直到转换成功为止我可以按照指定的类型打印。
但是Boost中应该有更简单的方法吧?我需要类似反向 lexical_cast
的东西...
I have a Map std::map<std::string, boost::any>
, which comes from the boost::program_options
package. Now I would like to print the content of that map:
for(po::variables_map::const_iterator it = vm.begin(); it != vm.end(); ++it) {
std::cerr << it->first << ": " << it->second << std::endl;
}
Unfortunately, that is not possible because boost::any
doesn't have an operator<<
defined.
What is the easiest way to print that map?
I could define my own output operator for any that automatically tries to cast each any
to an int, then double, then string, etc., each time ignoring errors and trying to cast until the cast is successful and I can print as the specified type.
But there should be an easier method in Boost? I'd need something like a reverse lexical_cast
...
发布评论
评论(9)
您可以使用
boost::spirit::hold_any
代替。它在这里定义:并且与
boost::any
完全兼容。与boost::any
相比,此类有两个不同之处:spirit::hold_any
更小、更快与boost::any
相比,operator<<()
和operator>>()
),允许无缝输入和输出spirit::hold_any
。唯一的限制是您不能输入空的
spirit::hold_any
,但它需要保存输入所期望的类型的实例(可能是默认构造的)。You could use
boost::spirit::hold_any
instead. It's defined here:and is fully compatible with
boost::any
. This class has two differences if compared toboost::any
:spirit::hold_any
smaller and faster thanboost::any
operator<<()
andoperator>>()
) defined, allowing to input and output aspirit::hold_any
seemlessly.The only limitation is that you can't input into an empty
spirit::hold_any
, but it needs to be holding a (possibly default constructed) instance of the type which is expected from the input.如果您可以将
boost::any
更改为其他类型,则可以使用 Boost.TypeErasure。如果您曾经想要创建一个类似于any
的类型,但仅支持在编译时支持这些特定操作的类型,那么这正适合您。在 Coliru 上直播
If you can change
boost::any
to another type, you can use Boost.TypeErasure. If you ever wanted to create a type that's likeany
, but only supporting types that support these particular operations at compile time, then this is just for you.Live On Coliru
不幸的是,对于 any ,唯一的方法是使用 type() 方法来确定 any 中包含的内容,然后使用 type() 对其进行强制转换>任意广播。显然,您必须启用 RTTI,但如果您使用any,则可能已经启用了 RTTI:
Unfortunately, with any the only way is to use the type() method to determine what is contained within any, then cast it with any_cast. Obviously you must have RTTI enabled, but you probably already do if you're using any:
定义一些辅助函数来输出到流:
您可以为某些类型定义特殊格式
或
然后为
boost::any
定义一个输出运算符,其中列出您想要尝试转换和输出的所有类型并且那么对于 value_type:
Define some aux function to output to stream:
You can define a special formatting for some types
or
Then define an output operator for
boost::any
where you list all types you want to try to cast and outputAnd then for a value_type:
其他答案中提出的类型开关列表可以通过使用 Boost MPL 的类型列表循环来改进(请参阅
mpl::for_each
和mpl::vector
)。以下代码为类型列表SupportedTypes
中给定的任何boost::any
定义一个运算符<<
,否则抛出异常。The list of type switches proposed in other answers can be improved with a loop over a type list using Boost MPL (see documentation of
mpl::for_each
andmpl::vector
). The following code defines anoperator<<
for anyboost::any
that is given in the type listSupportedTypes
and throws an exception otherwise.我认为你必须涵盖你必须打印的对象的每种可能情况......或者使用 boost::variant。
编辑:抱歉,我想我应该写为什么。
我认为这是因为,查看任何源代码,它似乎依赖于您在插入和获取数据时提供类型的事实。当您插入时,编译器会自动检测数据,因此您不必指定它。但是当你获取数据时,你应该使用any_cast,因为你不确定你得到的数据类型。
如果它以不同的方式工作并且数据类型是确定的,我认为就不需要 any_cast :)
相反,变体有一组有限的可能数据类型,并且此信息在某种程度上已注册,使您能够迭代变体容器的通用方式。
如果您需要这种操作 - 迭代一组通用值 - 我认为您应该使用变体。
I think you have to cover each possible case of objects you have to print... Or use boost::variant.
EDIT: Sorry, I thought I shall write WHY.
The reason why I think that is because, looking at any source code, it seems to rely on the fact that YOU provide the types when inserting and getting data. When you insert, data is automatically detected by the compiler, so you don't have to specify it. But when you get the data, you shall use any_cast, because you're not sure of the data type you're getting.
If it worked in a different way and data type was sure, I think that would be no need for any_cast :)
Instead, variant have a limited set of possible data types, and this information is somewhat registered, giving you the ability to iterate in a generic way a variant container.
If you need this kind of manipulation - iterating a generic set of values - I think you shall use variant.
尝试使用 xany https://sourceforge.net/projects/extendableany/?source=directory xany 类允许向任何现有功能添加新方法。顺便说一下,文档中有一个示例,它完全可以满足您的需求。
Try using xany https://sourceforge.net/projects/extendableany/?source=directory xany class allows to add new methods to any's existing functionality. By the way there is a example in documentation which does exactly what you want.
我没有重写我的类来使用
boost::spirit::hold_any
,而是创建了一种流boost::any
的方法,类似于 清单,但只在一处。虽然相当麻烦,但它允许我在代码中的任何位置传输 boost::any 变量。
能够从
boost:any
构造boost::spirit::hold_any
怎么样?Rather than re-writing my class to use
boost::spirit::hold_any
, I created a way to streamboost::any
, similar to what manifest suggested, but just in one place.Rather cumbersome, but it allows me to stream a
boost::any
variable anywhere in my code.How about being able to construct a
boost::spirit::hold_any
from aboost:any
?这次聚会有点晚了,但任何感兴趣的人都可以使用
std::tuple
和类似std::for_each
的模板来迭代元组。这是基于 ingomueller.net 在此线程中的答案。
我最近有一个案例,我创建了一个属性映射(从 XML 文件读取配置值,主要是基本类型,并将它们插入到
std::unordered_map
中,其中值类型为any
。出于调试目的,我希望能够打印整个映射及其键和值以及值的类型。在该项目中,我根本没有使用 Boost。 ,我使用了自己的
any
实现,但它与 boost::any 非常相似。插入运算符基本上如下所示:
for_each 模板如下所示 (C++14):
有了这个,只需使用StreamInserter 类或 Ingos 答案中显示的类似内容
希望有所帮助。
A little late for this party, but anyone that may be interested can also use
std::tuple
and astd::for_each
-like template that iterates over a tuple.This is based on the answer from ingomueller.net in this thread.
I had a recent case where I created a property map (reading configuration values, mainly fundamental types, from an XML file and inserting them into an
std::unordered_map
, where the value type is of typeany
. For debugging purposes I wanted to be able to print the entire map with its keys and values along with the type of the value.In that project I am not using Boost at all, I used my own
any
implementation, but its very similar to boost::any.The insertion operator basically looks like this:
The for_each template looks like this (C++14):
With this just use the
StreamInserter
class or something similar shown in Ingos answer.Hope this helps.