不知道类型的情况下流式传输std::any

5

我想在不知道值的情况下流式传输 std::any

我知道有std::any.type(),但我不确定如何在std::any_cast<type>(thatAny)中使用它。

这是我尝试的代码:

std::cout << std::any_cast<a.type()>(a) << std::endl;

type()是运行时值,而模板参数必须是编译时常量。 - François Andrieux
2
我会说,无论你试图完成什么任务,使用std::any都是错误的。 - StoryTeller - Unslander Monica
7
如果你已经有了这样的类型列表,为什么要使用std::any而不是std::variant<...> - MSalters
你尝试使用std::static_cast<void *>(type)了吗?这是将类型明确转换为void指针的简单方法。 - SPlatten
你可能想考虑使用boost.type_erasure库。它专门为此目的而设计。https://www.boost.org/doc/libs/1_68_0/doc/html/boost_typeerasure/basic.html - Richard Hodges
显示剩余2条评论
2个回答

10

你需要将如何流式传输的内容存储在某处。

有几种不同的方法。如果你可以集中列举或注册所有可以流式传输的类型,你可以创建从typeid到流式编码的映射,然后使用该映射来流式传输你特定的std::any

std::unordered_map< std::type_index, void(*)(std::any const&, std::ostream&)> streamers;

template<class T>
void add_streamer() {
  streamers[ typeid(T) ] = [](std::any const& a, std::ostream& os ) {
    os << std::any_cast<T>(a);
  };
}
template<class...Ts>
void add_streamers() {
  ( void(add_streamer<T>()), ... );
}

现在您可以进行流媒体:

void stream( std::ostream& os, std::any const& a ) {
  streamers[ a.type() ]( a, os ); // maybe check errors!
}

另一个方案是增强您的any实例。

struct streamable_any : std::any {
  void(*streamer)(std::ostream&, streamable_any const&) = nullptr;
  friend std::ostream& operator<<( std::ostream& os, streamable_any const& a ) {
    a.streamer( os, a );
    return os;
  }
  template<class T,
    std::enable_if_t<!std::is_same<std::decay_t<T>, streamable_any>{}, bool> = true
  >
  streamable_any( T&& t ):
    std::any( std::forward<T>(t) ),
    streamer([](std::ostream& os, streamable_any const& self ) {
      os << std::any_cast<std::decay_t<T>>(self);
    } )
  {}
};

现在,一个streamable_any只存储可流式传输的类型,并将如何进行流式传输的函数指针与实例一起存储。

更安全的streamable_any不会公开继承自std::any,因为通过转换到基类修改std::any将会破坏流式传输。这只是由于any_cast等操作带来的痛苦。

实时示例


我需要包含哪些内容?获取type_index和其他类型的错误。 - Mr.DeleteMyMessages
@steph 不,但完整的错误信息中可能会说明问题所在。只是需要时间来解码。 - Yakk - Adam Nevraumont
@steph 是的,wstreamable_any 稍微有些不同。 - Yakk - Adam Nevraumont
另外,您能否友好地解释一下 std::enable_if_t 的保护作用?我似乎无法触发它... - steph643
1
@steph643 这样做是为了避免它优先于非常量拷贝构造函数streamable_any(streamable_any&);我希望它能调用streamable_any(streamable_any const&),以及一些类似的情况。 - undefined
显示剩余2条评论

2

这并非直接可行。

然而,如果您有一个T,不要直接存储它,而是存储{T, [](T const& t) { using std::to_string; return to_string(t); }}。也就是说,对于每个T,都存储一个序列化该特定T的lambda表达式。

另外,您可以保留std::any,但将其包装在自定义类型中,并在std::any旁边存储适当的[](std::any const& a) { return to_string(std::any_cast<T>(a));}。例如,如果插入了一个int,则还会创建并存储一个[](std::any const& a) { return to_string(std::any_cast<int>(a));}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接