提问人:Vinod 提问时间:8/15/2019 最后编辑:πάντα ῥεῖVinod 更新时间:8/15/2019 访问量:293
关于 std::add_pointer 实现的问题
A question regarding the implementation of 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 类型,该类型 是指向被引用类型的指针。
否则,如果 T 命名对象类型,则函数类型不是 cv- 或 ref-qualified 或 (可能是 cv 合格的) void 类型,提供 成员 typedef 类型,即 T* 类型。
否则(如果 T 是 cv 或 ref 限定的函数类型),则提供 成员 typedef 类型,即 T 类型。
在上面的(可能的)实现代码中,显然派生自 .struct add_pointer
detail::try_add_pointer<T>(0)
从 take 参数的重载返回的类型派生,将成员解析为上述三种可能性之一背后的逻辑是什么?具体来说,这如何解决 if is a or qualified 函数类型的可能性?detail::try_add_pointer<T>
int
typedef type
T
cv-
ref-
答:
继承只是使用包装器(形成有效的返回类型已经需要)以最小的努力定义特征的一种方式。重载技巧依赖于这样一个事实,即非引用类型的标识,并且(处理引用)除非根本没有这样的类型。在这种情况下,SFINAE 会终止过载并选择 (其中 just 被生成)。type_identity
std::remove_reference
std::add_pointer<T>
T*
int
...
T
关键在于了解过载解决的工作原理。代入意味着生成一个重载集,该重载集将始终包含至少一个成员(变量参数重载)。detail::try_add_pointer<T>(0)
T
detail::try_add_pointer
在过载解决 (SFINAE) 期间是否丢弃过载,取决于代入 的成功与否。当替换成功时,重载存在,并且在 0 的重载分辨率方面匹配得更好(与任何其他转换序列相比,省略号是最差的匹配)。无论哪种方式,无论在重载解析中选取哪个重载,都将解析为具有嵌套成员的内容。int
T
typename std::remove_reference<T>::type*
decltype(detail::try_add_pointer<T>(0))
::type
因此,让我们逐案分析:
“如果 T 是引用类型” - 让我们标记它。然后是.我们可以形成引用的类型也是我们可以形成指针的类型。所以是 良好的 (它是 ),并且存在第一个重载。它在过载分辨率中被拾取。其返回类型的嵌套是 。
T = T2&
std::remove_reference<T>::type
T2
std::remove_reference<T>::type*
T2*
::type
T2*
“否则,如果 T 命名一个对象类型,一个不是 cv 或 ref 限定的函数类型,或者一个(可能是 cv 限定的)void 类型” - 在这种情况下,只是 。我们可以形成指向上一个列表中任何类型的指针,因此再次形成良好的格式(它是 )。第一个重载再次存在,并在重载解决中被拾取。其返回类型的嵌套是 。
std::remove_reference<T>::type
T
std::remove_reference<T>::type*
T*
::type
T*
“否则(如果 T 是 cv 或 ref 限定的函数类型)” - 有趣的部分。这说的是像 .这里又是.但是我们不允许形成指向的指针,基本语言禁止它。因此格式不正确,对于此过载解决方案,第一个过载被忽略。只剩下第二个过载,它是过载解决拾取的那个。其返回类型的嵌套是 。
void (int) const&
std::remove_reference<T>::type
T
T
std::remove_reference<T>::type*
::type
T
评论
If T is a reference type, then provides the member typedef type which is a pointer to the referred type.
What is the logic behind deriving from the type returned by the overload of
struct add_pointer :
using add_pointer =