关于 std::add_pointer 实现的问题

A question regarding the implementation of std::add_pointer

提问人:Vinod 提问时间:8/15/2019 最后编辑:πάντα ῥεῖVinod 更新时间:8/15/2019 访问量:293

问:

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_pointerdetail::try_add_pointer<T>(0)

从 take 参数的重载返回的类型派生,将成员解析为上述三种可能性之一背后的逻辑是什么?具体来说,这如何解决 if is a or qualified 函数类型的可能性?detail::try_add_pointer<T>inttypedef typeTcv-ref-

C++ 标准

评论

0赞 Jay 8/15/2019
上述(可能的)实现的描述如下: 然后立即删除此评论。GN DD:问题是什么?我们在解决什么,我什至不确定这是否真的有意义......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
1赞 Maxim Egorushkin 8/15/2019
取而代之的是.struct add_pointer : using add_pointer =
0赞 Jay 8/15/2019
O 礼仪 所以这意味着语法师是不同的 rigth 符号 数字 那是什么评论。
0赞 Jay 8/15/2019
我认为这意味着您正在引用命名空间或类似的东西 4 real

答:

1赞 Davis Herring 8/15/2019 #1

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

4赞 StoryTeller - Unslander Monica 8/15/2019 #2

关键在于了解过载解决的工作原理。代入意味着生成一个重载集,该重载集将始终包含至少一个成员(变量参数重载)。detail::try_add_pointer<T>(0)Tdetail::try_add_pointer

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

因此,让我们逐案分析:

  1. “如果 T 是引用类型” - 让我们标记它。然后是.我们可以形成引用的类型也是我们可以形成指针的类型。所以是 良好的 (它是 ),并且存在第一个重载。它在过载分辨率中被拾取。其返回类型的嵌套是 。T = T2&std::remove_reference<T>::typeT2std::remove_reference<T>::type*T2*::typeT2*

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

  3. “否则(如果 T 是 cv 或 ref 限定的函数类型)” - 有趣的部分。这说的是像 .这里又是.但是我们不允许形成指向的指针,基本语言禁止它。因此格式不正确,对于此过载解决方案,第一个过载被忽略。只剩下第二个过载,它是过载解决拾取的那个。其返回类型的嵌套是 。void (int) const&std::remove_reference<T>::typeTTstd::remove_reference<T>::type*::typeT