【问题标题】:Is it absolutely necessary for std::any_cast() and std::get_if(std::variant) to take pointer as an argument?std::any_cast() 和 std::get_if(std::variant) 是否绝对有必要将指针作为参数?
【发布时间】:2016-12-01 18:08:54
【问题描述】:

对于std::anystd::variant,我们有函数来请求对象关于当前包含的值,如果不能满足请求,则返回nullptr(就像dynamic_cast 一样):

template<class ValueType>
const ValueType *any_cast(const any *operand);

template<class ValueType>
ValueType *any_cast(any *operand);

template <class T, class... Types>
std::add_pointer_t<T> get_if(variant<Types...> *pv);

template <class T, class... Types>
std::add_pointer_t<const T> get_if(const variant<Types...> *pv);

两者都将指针作为参数。为什么?它效率不高。实现每次都检查参数是否不是nullptrnullptr 论点有任何意义吗?

该函数可以是类成员,也可以将引用作为参数(名称可能略有不同)。这种次优设计的原因是什么?只是模仿dynamic_cast的界面?

【问题讨论】:

  • 您正在使用类型擦除的容器并获取其存储值,并且您担心与nullptr 比较的性能?
  • 是的。我担心每一个可避免的开销。它只是丑陋的界面
  • 这些函数的某些版本将引用作为参数。他们只是抛出失败(而不是返回nullptr)。
  • 是的,我现在。但它们是不同类型的动作。它们是断言而不是请求。
  • @Nicol 有道理。但这不是我的问题的答案

标签: c++ c++17


【解决方案1】:

为了将函数名称保留为其中之一,并使其像内置的 _cast 运算符一样工作,any_cast 可以使用引用或指针。

指针版本接受一个指针,如果它包含您要求的内容,则返回一个指向该元素的指针。否则返回 nullptr。

参考版本采用参考,如果它不包含您要求的内容,则抛出。

他们使用参数的指针来区分这两个选项,匹配dynamic_cast&lt;T&amp;&gt;(x)dynamic_cast&lt;T*&gt;(&amp;x) 的工作方式。

内联将很容易。针对指向自动存储对象的指针的空值的内联检查很容易优化为“非空值”,因为自动存储对象的地址没有一致的方法可以使之为空指针。

因此,在发布的几乎所有情况下,我都希望 check-if-nullptr 的开销为零。一个例外是代码有一个指向any(或变体)的指针,它有一些证据证明这个指向any 的指针不是编译器不太可能知道的空值,然后它将它传递给any_cast .如果他们没有使用pointer-to-indicate-pointer-return-type技巧,则可以使用any_cast_to_ptr(any&amp;)“冒险”UB并无条件地取消引用该指针。

真正缺少的 API 是 dangerous_any_cast,如果类型不匹配,它只会执行 UB,因为关于 any 状态的非本地证明知识似乎比关于指针无效性的非本地证明知识更有可能 -到任何地方。

这种情况很少见。

至于get_if vs get,不知道为什么没有get_if(variant&lt;???&gt;&amp;)重载。

【讨论】:

  • get_if 仅是指针。参考/投掷版本为get
猜你喜欢
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 2021-12-02
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多