以前没有意识到存在std::addressof,为什么它存在对我来说是有道理的:作为一种在存在重载的情况下获取地址的方法operator&.然而,实施稍微不透明.来自gcc 4.7.1:
template<typename _Tp>
inline _Tp*
__addressof(_Tp& __r) _GLIBCXX_NOEXCEPT
{
return reinterpret_cast<_Tp*>
(&const_cast<char&>(reinterpret_cast<const volatile char&>(__r)));
}
Run Code Online (Sandbox Code Playgroud)
将reinterpret_cast<_Tp*>是显而易见的.剩下的就是黑魔法.有人可以打破这实际上是如何工作的吗?
sya*_*yam 30
__r哪种类型_Tp&reinterpret_cast"编到一个char&,以确保能够以后采取它的地址而不用担心一个重载operator&在原有类型; 实际上它被强制转换,const volatile char&因为即使它们不存在reinterpret_cast也总能合法地添加const和volatile限定,但是如果它们存在则它不能删除它们(这确保了无论什么限定符_Tp最初,它们都不会干扰转换).const_cast'只是char&,删除限定符(现在合法!const_cast可以做reinterpret_cast与限定符无关的事情).&(现在我们有一个简单的char*)reinterpret_cast'回溯_Tp*(包括原始const和volatile限定符,如果有的话).编辑:由于我的答案已被接受,我将彻底并补充说,char作为中间类型的选择是由于对齐问题,以避免触发未定义的行为.有关完整说明,请参阅@ JamesKanze的评论(在问题下).感谢詹姆斯如此清楚地解释它.
Fil*_*efp 12
当你想到它时,它实际上非常简单,为了在过载的前提下获得对象/函数的真实地址,operator&你需要将对象视为不同于实际的东西,某些类型不能有重载的运算符. .内在类型(如char).
A char没有对齐,可以驻留在任何其他对象可以的任何地方,并且可以说; 将对象转换为对char的引用是一个非常好的开始.
但是在做什么时会涉及黑魔法reinterpret_cast<const volatile char&>呢?
为了从执行中重新解释返回的指针,addressof我们最终会想要丢弃限定符,例如const和volatile(最后用一个简单的引用char).这两个可以轻松添加reinterpret_cast,但要求删除它们是非法的.
T1 const a; reinterpret_cast<T2&> (a);
/* error: reinterpret_cast from type ‘...’ to type ‘...’ casts away qualifiers */
Run Code Online (Sandbox Code Playgroud)
这是一个"更安全而不是遗憾"的技巧."让我们添加它们,以防万一,我们将在以后删除它们."
稍后我们抛弃限定符(const和volatile)以const_cast<char&>得到一个简单的引用char,这个结果,作为最后一步,转回指向我们传入实现的任何类型的指针.
这个阶段的一个相关问题是为什么我们没有跳过使用reinterpret_cast并直接进入const_cast?这也有一个简单的答案:const_cast可以添加/删除限定符,但它不能更改基础类型.
T1 a; const_cast<T2&> (a);
/* error: invalid const_cast from type ‘T1*’ to type ‘T2*’ */
Run Code Online (Sandbox Code Playgroud)
馅饼可能并不容易,但是当它得到它时它确实味道很好..
简短版本:
operator&不能超载char.因此,类型被转换为char引用以获得保证为真实地址的内容.
由于对const_cast和的限制,转换是在两个演员阵容中完成的reinterpret_cast.
版本较长:
它正在进行三次连续演员表演.
reinterpret_cast<const volatile char&>
Run Code Online (Sandbox Code Playgroud)
这实际上是铸造到了char&.在const和volatile只存在,因为_Tp可能是const或volatile,并且reinterpret_cast可以添加这些,但将无法删除它们.
const_cast<char&>
Run Code Online (Sandbox Code Playgroud)
现在,const和volatile已被删除. const_cast也许那样做.
reinterpret_cast<_Tp*> &(result)
Run Code Online (Sandbox Code Playgroud)
现在获取地址,并将类型转换回指向原始类型的指针.
从内到外:
首先它将__r类型转换为const volatile char&:它正在转换为一个char&因为它是一种肯定没有重载的类型,operator&它做了一些时髦的事情.那const volatile是因为那些是限制,它们可以被添加但不被带走reinterpret_cast._Tp可能已经const和/或volatile,在这种情况下,在这个演员阵容中需要一个或两个.如果没有,那么演员只是不必要地添加它们,但它是为最严格的演员而写的.
接下来,带走const volatile你需要const_cast,这导致了接下来的部分...... const_cast<char&>.
从那里他们只需要获取地址并将其转换为您想要的类型,a _Tp*.请注意,这_Tp可能是const和/或volatile,这意味着此时可以添加这些内容.