问题描述
可能的实现
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键入
到上述三种可能性之一?具体来说,如果 T
是 cv-
或 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.
那么让我们逐案分析:
如果 T 是引用类型" - 让我们将其标记为
T = T2&
.那么std::remove_reference::type
就是T2
.我们可以形成引用的类型也是我们可以形成指针的类型.所以std::remove_reference::type*
是格式良好的(它是T2*
),并且存在第一个重载.它是在重载解析中提取的.其返回类型的嵌套::type
为T2*
.
"If T is a reference type" - Let's mark it
T = T2&
. Thenstd::remove_reference<T>::type
isT2
. The types to which we may form a reference are also the types to which we may form a pointer. Sostd::remove_reference<T>::type*
is well-formed (it'sT2*
), and the first overload exists. It's picked up in overload resolution. The nested::type
of its return type isT2*
.
否则,如果 T 命名了一个对象类型、一个不是 cv 或 ref 限定的函数类型,或者一个(可能是 cv 限定的)void 类型" - 在这种情况下 std::remove_reference::type
就是 T
.我们可以形成一个指向前面列表中任何类型的指针,因此 std::remove_reference<T>::type*
再次形成良好的结构(它是 T*
).第一个重载再次存在并在重载解析中被拾取.其返回类型的嵌套 ::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" - 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*
是格式错误的,对于这个重载决议,第一个重载被忽略.只剩下第二个重载,它是由重载决议拾取的那个.其返回类型的嵌套 ::type
是 T
.
"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 实现的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!