【问题标题】:A question regarding the implementation of std::add_pointer关于 std::add_pointer 实现的问题
【发布时间】:2019-08-15 07:14:37
【问题描述】:

来自std::add_pointer

可能的实现

namespace detail {

template <class T>
struct type_identity { using type = T; }; // or use std::type_identity (since C++20)

template <class T>
auto try_add_pointer(int) -> type_identity<typename std::remove_reference<T>::type*>;
template <class T>
auto try_add_pointer(...) -> type_identity<T>;

} // namespace detail

template <class T>
struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};

上述(可能的)实现的描述如下:

如果 T 是引用类型,则提供成员 typedef type 是指向被引用类型的指针。

否则,如果 T 命名一个对象类型,一个函数类型不是 cv- 或 ref-qualified,或(可能是 cv-qualified)void 类型,提供 成员typedef type,即类型T*。

否则(如果 T 是 cv 或 ref 限定的函数类型),则提供 成员typedef type,即类型T。

在上面的(可能的)实现代码中,显然struct add_pointer 派生自detail::try_add_pointer&lt;T&gt;(0) 返回的类型。

detail::try_add_pointer&lt;T&gt; 的重载返回的类型派生出int 参数,以将成员typedef type 解析为上述三种可能性之一的逻辑是什么?具体来说,如果Tcv-ref-qualified 函数类型,这将如何解决这种可能性?

【问题讨论】:

  • 上述(可能的)实现的描述为:If T is a reference type, then provides the member typedef type which is a pointer to the referred type. 然后立即删除此评论。 GN DD 有什么问题吗?我们在解决什么What is the logic behind deriving from the type returned by the overload of 我什至不确定这是否真的有意义......
  • 可以是struct add_pointer : ,而不是using add_pointer =
  • O rite 所以这意味着语法不同 rigth Symbols Numbers 那条评论是什么。
  • 我认为这意味着你正在引用一个命名空间或类似的东西 4 real

标签: c++ std


【解决方案1】:

关键在于了解detail::try_add_pointer&lt;T&gt;(0) 的重载解析是如何工作的。将T 替换为detail::try_add_pointer 是为了生成一个始终包含至少一个成员(变量参数重载)的重载集。

在重载解析期间(SFINAE)是否丢弃采用int 的重载取决于将T 替换为typename std::remove_reference&lt;T&gt;::type* 是否成功。当替换成功时,重载存在,并且在重载分辨率中更好地匹配 0(与任何其他转换序列相比,省略号是最差的匹配)。无论哪种方式,无论在重载解析中选择哪个重载,decltype(detail::try_add_pointer&lt;T&gt;(0)) 都会解析为具有嵌套 ::type 成员的内容。

让我们逐案分析:

  1. “如果 T 是引用类型” - 让我们将其标记为 T = T2&amp;。那么std::remove_reference&lt;T&gt;::type 就是T2。我们可以形成引用的类型也是我们可以形成指针的类型。所以std::remove_reference&lt;T&gt;::type* 格式正确(它是T2*),并且存在第一个重载。它在重载决议中被拾起。其返回类型的嵌套::typeT2*

  2. “否则,如果 T 命名了一个对象类型、一个不是 cv 或 ref 限定的函数类型,或者一个(可能是 cv 限定的)void 类型”——在这种情况下,std::remove_reference&lt;T&gt;::type 就是 @ 987654338@。我们可以形成一个指向前一个列表中任何类型的指针,因此std::remove_reference&lt;T&gt;::type* 的格式再次正确(它是T*)。第一个重载再次存在并在重载决议中被拾取。其返回类型的嵌套::typeT*

  3. “否则(如果 T 是 cv 或 ref 限定的函数类型)” - 有趣的一点。这涉及到像void (int) const&amp; 这样的类型。这里std::remove_reference&lt;T&gt;::type 又是T。但是我们不允许形成指向T的指针,基础语言禁止这样做。因此std::remove_reference&lt;T&gt;::type* 格式不正确,并且对于此重载解决方案,第一个重载被忽略。只剩下第二个重载,它是重载决议所拾取的。其返回类型的嵌套::typeT

【讨论】:

    【解决方案2】:

    继承只是使用type_identity 包装器(已经需要形成有效的返回类型)以最小的努力定义特征的一种方式。重载技巧依赖于这样一个事实:std::remove_reference 是非引用类型的标识,并且(已处理引用)std::add_pointer&lt;T&gt;T*,除非根本没有 没有这样的类型 .在这种情况下,SFINAE 会终止 int 过载并选择 ...(其中仅生成 T)。

    【讨论】:

      猜你喜欢
      • 2023-03-17
      • 2011-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多