【问题标题】:C++: check if the value stored in std::any is integralC++:检查存储在 std::any 中的值是否是整数
【发布时间】:2021-07-19 01:05:27
【问题描述】:

std::any 中存储了一个值,我想知道它是整数值(charshortintlong,有符号和无符号)还是浮点值(@ 987654328@、double) 或其他。

如果我只需要检查 int 值,我会这样做:

std::any a;
if (a.type() == typeid(int)) {
  // do some logic for int
}

但是为 C++ 中的所有整数类型做一个巨大的if (a.type() == typeid(int) || a.type() == typeid(signed char)...) 似乎......不好。

如果我可以以某种方式访问​​T 类型,我可以使用type_traits 中的is_arithmetic<T>,但我没有,我只有std::any#type(),它返回std::type_info

有没有办法在if 条件中不出现许多析取现象?

(如果重要的话,我使用的是 C++20)

【问题讨论】:

  • std::any_cast 并捕获抛出的异常,如果它是错误的类型?但请注意,int 可以转换为几乎任何其他数字类型,因此这可能不起作用。话虽如此,一般来说,使用typeid 选择程序路径通常是糟糕设计的标志。
  • 这就是 std any 的工作方式,这就是它的局限性。如果您想要更花哨的东西,请使用您的方式类型擦除(例如,构建在 std any 之上)或使用其他库,如 Boost.TypeErasure boost.org/doc/libs/1_76_0/doc/html/boost_typeerasure.html。关键是您正在寻找基于概念的类型擦除而不是基于类型。

标签: c++ c++20 stdany


【解决方案1】:

std::any 是一个类型擦除类。

它只记住确切的类型,以及转换回该确切类型的能力(以及如何复制/移动/销毁它)。

如果您想记住有关存储类型的其他事实,您必须自己完成这项工作。

如果不检查确切的T,就无法访​​问std::any 中的T

一般来说,使用std::any 在没有控制的情况下将“任何东西”推入其中会导致一团糟。 std::any 允许您使用一组“开放”类型来执行此操作,因此您可以安全地将数据从一个代码点传递到另一个代码点,而中间代码不需要知道它是什么。

它无法让您使用未知类型生成类型感知代码。


要解决您的问题,有多种解决方案。

  1. 如果您支持的类型集已关闭(以某种方式修复),请使用 std::variant

  2. 如果类型集大部分是封闭的,请使用std::variant< bunch, of, types, std::any >。然后您可以将“大部分关闭”的类型处理为variant。如果类型输入可以转换为任何其他类型,则使用阻止转换为 std::any 的代码可能是明智的。

  3. 如果您愿意编写自己的类型擦除,您可以自己编写或增加std::any 的额外信息。

  4. 您可以编写一个实用函数来执行大量 if 语句,可能使用模板,在时间上与类型数量成线性关系。

对于 1/2,

auto is_integral_f = [](auto&& x){ return std::is_integral<std::decay_t<decltype(x)>>{}; };

std::variant<int,char,unsigned int, long, double, std::any> bob;
bob = 3;
assert( std::visit( is_integral_f, bob ) );

对于 3,here is an example 的引擎使这种方式的类型擦除更简单一些;自己写是可以的。然后我们简单地:

auto is_integral = any_method<bool()>{ is_integral_f };

super_any<decltype(is_integral)> my_any;

my_any bob = 3;
my_any alice = 3.14;
assert( (bob->*is_integral)() );
assert( !(alice->*is_integral)() );

4,

template<class...Ts>
bool is_any_of_types( std::any const& a ) {
  return (( a.type() == typeid(Ts) ) || ... );
}

sizeof...(Ts) 中是线性的。

如果Ts... 很大,您可能会喜欢散列,但我怀疑它会变得足够大。您仍然需要自己枚举类型; is_integral&lt;T&gt; 不能被 C++ 语言反转。

【讨论】:

  • 对一组允许的 int 类型的std::type_indexes 进行查询可能是一个选项
  • @sopel 是的,甚至是哈希表。
猜你喜欢
  • 2017-06-12
  • 1970-01-01
  • 1970-01-01
  • 2023-02-02
  • 2020-11-21
  • 2014-10-18
  • 2015-06-18
  • 1970-01-01
  • 2023-01-12
相关资源
最近更新 更多