关于 std::add_pointer 实施的问题
A question regarding the implementation of std::add_pointer
Possible implementation
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)) {};
上述(可能的)实现的描述如下:
If T is a reference type, then provides the member typedef type which
is a pointer to the referred type.
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*.
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<T>(0)
返回的类型。
从采用 int
参数的 detail::try_add_pointer<T>
的重载返回的类型派生,将成员 typedef type
解析为上述三种可能性之一的背后逻辑是什么?具体来说,这如何解决 T
是 cv-
或 ref-
限定函数类型的可能性?
继承只是使用 type_identity
包装器(已经需要形成有效的 return 类型)以最小的努力定义特征的一种方式。重载技巧依赖于 std::remove_reference
是非引用类型的标识,并且(处理了引用)std::add_pointer<T>
是 T*
除非存在 no这样的类型。在这种情况下,SFINAE 会终止 int
过载并选择 ...
(仅生成 T
)。
关键在于理解 detail::try_add_pointer<T>(0)
的重载解析是如何工作的。将 T
替换为 detail::try_add_pointer
意味着生成一个重载集,该重载集将始终包含至少一个成员(变量参数重载)。
是否在重载决议(SFINAE)期间丢弃带int
的重载取决于将T
替换为typename std::remove_reference<T>::type*
是否成功。当替换成功时,重载存在,并且在 0 的重载解析中是更好的匹配(与任何其他转换序列相比,省略号是最差的可能匹配)。无论哪种方式,无论在重载解析中选择哪个重载,decltype(detail::try_add_pointer<T>(0))
都将解析为具有嵌套 ::type
成员的内容。
那么让我们逐案分析:
"If T is a reference type" - 让我们标记它 T = T2&
。那么std::remove_reference<T>::type
就是T2
。我们可以形成引用的类型也是我们可以形成指针的类型。所以 std::remove_reference<T>::type*
是合式的(它是 T2*
),并且第一个重载存在。它在过载解决方案中被拾取。其return类型的嵌套::type
为T2*
.
"Otherwise, if T names an object type, a function type that is not cv- or ref-qualified, or a (possibly cv-qualified) void type" - 在这种情况下 std::remove_reference<T>::type
就是 T
。我们可以形成一个指向前面列表中任何类型的指针,因此 std::remove_reference<T>::type*
再次形成良好(并且它是 T*
)。第一个重载再次存在并在重载决议中被拾取。其return类型的嵌套::type
为T*
.
"Otherwise (if T is a cv- or ref-qualified function type)" - 有趣的一点。这就是像 void (int) const&
这样的类型。这里 std::remove_reference<T>::type
又是 T
。但是我们不允许形成指向T
的指针,基础语言是禁止的。因此 std::remove_reference<T>::type*
格式错误,对于此重载决议,第一个重载将被忽略。只剩下第二个重载,它是由重载决议拾取的。其 return 类型的嵌套 ::type
为 T
.
Possible implementation
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)) {};
上述(可能的)实现的描述如下:
If T is a reference type, then provides the member typedef type which is a pointer to the referred type.
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*.
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<T>(0)
返回的类型。
从采用 int
参数的 detail::try_add_pointer<T>
的重载返回的类型派生,将成员 typedef type
解析为上述三种可能性之一的背后逻辑是什么?具体来说,这如何解决 T
是 cv-
或 ref-
限定函数类型的可能性?
继承只是使用 type_identity
包装器(已经需要形成有效的 return 类型)以最小的努力定义特征的一种方式。重载技巧依赖于 std::remove_reference
是非引用类型的标识,并且(处理了引用)std::add_pointer<T>
是 T*
除非存在 no这样的类型。在这种情况下,SFINAE 会终止 int
过载并选择 ...
(仅生成 T
)。
关键在于理解 detail::try_add_pointer<T>(0)
的重载解析是如何工作的。将 T
替换为 detail::try_add_pointer
意味着生成一个重载集,该重载集将始终包含至少一个成员(变量参数重载)。
是否在重载决议(SFINAE)期间丢弃带int
的重载取决于将T
替换为typename std::remove_reference<T>::type*
是否成功。当替换成功时,重载存在,并且在 0 的重载解析中是更好的匹配(与任何其他转换序列相比,省略号是最差的可能匹配)。无论哪种方式,无论在重载解析中选择哪个重载,decltype(detail::try_add_pointer<T>(0))
都将解析为具有嵌套 ::type
成员的内容。
那么让我们逐案分析:
"If T is a reference type" - 让我们标记它
T = T2&
。那么std::remove_reference<T>::type
就是T2
。我们可以形成引用的类型也是我们可以形成指针的类型。所以std::remove_reference<T>::type*
是合式的(它是T2*
),并且第一个重载存在。它在过载解决方案中被拾取。其return类型的嵌套::type
为T2*
."Otherwise, if T names an object type, a function type that is not cv- or ref-qualified, or a (possibly cv-qualified) void type" - 在这种情况下
std::remove_reference<T>::type
就是T
。我们可以形成一个指向前面列表中任何类型的指针,因此std::remove_reference<T>::type*
再次形成良好(并且它是T*
)。第一个重载再次存在并在重载决议中被拾取。其return类型的嵌套::type
为T*
."Otherwise (if T is a cv- or ref-qualified function type)" - 有趣的一点。这就是像
void (int) const&
这样的类型。这里std::remove_reference<T>::type
又是T
。但是我们不允许形成指向T
的指针,基础语言是禁止的。因此std::remove_reference<T>::type*
格式错误,对于此重载决议,第一个重载将被忽略。只剩下第二个重载,它是由重载决议拾取的。其 return 类型的嵌套::type
为T
.