本文介绍了一个关于 std::add_pointer 实现的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自 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)) {};

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

The description for the above (possible) implementation reads:

如果 T 是引用类型,则提供成员 typedef 类型是指向所引用类型的指针.

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

Otherwise, if T names an object type, a function type that is not cv- or ref-qualified, or a (possibly cv-qualified) void type, provides the member typedef type which is the type T*.

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

Otherwise (if T is a cv- or ref-qualified function type), provides the member typedef type which is the type T.

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

In the (possible) implementation code above, apparently struct add_pointer derives from the type returned by detail::try_add_pointer<T>(0).

detail::try_add_pointer<T> 的重载返回的类型派生的逻辑是什么,以 int 参数解析成员 typedef键入 到上述三种可能性之一?具体来说,如果 Tcv-ref- 限定的函数类型,这如何解决这种可能性?

What is the logic behind deriving from the type returned by the overload of detail::try_add_pointer<T> taking int argument, to resolve the member typedef type to one of the three possibilities described above? Specifically, how does this address the possibility if T is a cv- or ref-qualified function type?

推荐答案

关键在于理解 detail::try_add_pointer(0) 的重载解析是如何工作的.将 T 替换为 detail::try_add_pointer 意味着生成一个重载集,该集将始终包含至少一个成员(可变参数重载).

The key is in understanding how overload resolution for detail::try_add_pointer<T>(0) works. Substituting T into detail::try_add_pointer is meant to produce an overload set that will always contain at least one member (the variable argument overload).

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

Whether or not the overload taking an int is discarded during overload resolution (SFINAE) is determined by the success of substituting T into typename std::remove_reference<T>::type*. When substitution succeeds, the overload exists, and is a better match in overload resolution for 0 (ellipsis are the worst possible match compared an any other conversion sequence). Either way, whichever overload is picked up in overload resolution, decltype(detail::try_add_pointer<T>(0)) will resolve to something that has a nested ::type member.

那么让我们逐案分析:

  1. 如果 T 是引用类型" - 让我们将其标记为 T = T2&.那么 std::remove_reference::type 就是 T2.我们可以形成引用的类型也是我们可以形成指针的类型.所以 std::remove_reference::type* 是格式良好的(它是 T2*),并且存在第一个重载.它是在重载解析中提取的.其返回类型的嵌套::typeT2*.

  1. "If T is a reference type" - Let's mark it T = T2&. Then std::remove_reference<T>::type is T2. The types to which we may form a reference are also the types to which we may form a pointer. So std::remove_reference<T>::type* is well-formed (it's T2*), and the first overload exists. It's picked up in overload resolution. The nested ::type of its return type is T2*.

否则,如果 T 命名了一个对象类型、一个不是 cv 或 ref 限定的函数类型,或者一个(可能是 cv 限定的)void 类型" - 在这种情况下 std::remove_reference::type 就是 T.我们可以形成一个指向前面列表中任何类型的指针,因此 std::remove_reference<T>::type* 再次形成良好的结构(它是 T*).第一个重载再次存在并在重载解析中被拾取.其返回类型的嵌套 ::typeT*.

"Otherwise, if T names an object type, a function type that is not cv- or ref-qualified, or a (possibly cv-qualified) void type" - In this case std::remove_reference<T>::type is simply T. We can form a pointer to any of the types in the previous list, and so std::remove_reference<T>::type* is well formed again (and it's T*). The first overload again exists and is picked up in overload resolution. The nested ::type of its return type is T*.

否则(如果 T 是 cv 或 ref 限定的函数类型)"——有趣的一点.这涉及到像 void (int) const& 这样的类型.这里std::remove_reference::type 也是T.但是我们不允许形成指向 T 的指针,基础语言禁止它.因此 std::remove_reference::type* 是格式错误的,对于这个重载决议,第一个重载被忽略.只剩下第二个重载,它是由重载决议拾取的那个.其返回类型的嵌套 ::typeT.

"Otherwise (if T is a cv- or ref-qualified function type)" - The interesting bit. This speaks of types like void (int) const&. Here again std::remove_reference<T>::type is T. But we are not allowed to form a pointer to T, the base language prohibits it. Therefore std::remove_reference<T>::type* is ill-formed, and for this overload resolution the first overload is disregarded. Left with only the second overload, it's the one picked up by overload resolution. The nested ::type of its return type is T.

这篇关于一个关于 std::add_pointer 实现的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-27 14:12
查看更多