更新: C ++ 11では、のstd::addressof代わりにを使用できますboost::addressof。
最初にBoostからコードをコピーして、コンパイラーがビットを回避するようにします。
template<class T>
struct addr_impl_ref
{
T & v_;
inline addr_impl_ref( T & v ): v_( v ) {}
inline operator T& () const { return v_; }
private:
addr_impl_ref & operator=(const addr_impl_ref &);
};
template<class T>
struct addressof_impl
{
static inline T * f( T & v, long ) {
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
}
static inline T * f( T * v, int ) { return v; }
};
template<class T>
T * addressof( T & v ) {
return addressof_impl<T>::f( addr_impl_ref<T>( v ), 0 );
}
関数への参照を渡すとどうなりますか?
注:addressof関数へのポインターでは使用できません
C ++では、if void func();が宣言されている場合、funcは引数を取らず、結果を返さない関数への参照です。関数へのこの参照は、関数へのポインタに簡単に変換できます@Konstantin-from:13.3.3.2によると両方ともT &、T *関数と区別できません。1つ目はID変換で、2つ目は「完全一致」ランク(13.3.3.1.1表9)を持つ関数からポインターへの変換です。
関数 pass through への参照addr_impl_refは、の選択に対するオーバーロードの解決にあいまいさがあり、これは最初であり、(Integral Conversion)に昇格できるfダミー引数のおかげで解決されます。0intlong
したがって、単純にポインタを返します。
変換演算子を使用して型を渡すとどうなりますか?
変換演算子がa T*を生成する場合、あいまいさf(T&,long)があります。f(T*,int)最初の引数で変換演算子が呼び出されている間、2番目の引数には統合プロモーションが必要です(@litbに感謝)
それがaddr_impl_ref始まるときです。C++標準では、変換シーケンスには最大で1つのユーザー定義の変換が含まれるように規定されています。型をラップしaddr_impl_ref、変換シーケンスの使用を強制することにより、型に付属する変換演算子をすべて「無効」にします。
したがって、f(T&,long)過負荷が選択されます(および統合プロモーションが実行されます)。
他のタイプの場合はどうなりますか?
したがって、f(T&,long)タイプがT*パラメータと一致しないため、オーバーロードが選択されます。
注:Borlandの互換性に関するファイル内のコメントから、配列はポインターに減衰しませんが、参照によって渡されます。
このオーバーロードで何が起こりますか?
operator&型が過負荷になっている可能性があるため、型には適用しないでください。
reinterpret_castこの作業に使用できる標準が保証されています(@Matteo Italiaの回答:5.2.10 / 10を参照)。
Boostは、コンパイラの警告を回避するための修飾子constといくつかの便利な機能を追加しvolatileます(そしてconst_castそれらを削除するために適切にa を使用します)。
- キャスト
T&するchar const volatile&
- ストリップ
constとvolatile
&オペレーターに住所を申請する
- にキャストバックする
T*
const/ volatileジャグリングは黒魔術のビットであり、それは(かなり4つのオーバーロードを提供するよりも)作業を簡素化しません。以来という注意T修飾されていない、私たちが渡した場合はghost const&、その後T*であるghost const*ので、修飾子は本当に失われていません、。
編集:ポインターオーバーロードは関数へのポインターに使用されます。上記の説明を多少修正しました。なぜそれが必要なのかはまだわかりません。
次のideone出力は、これをいくらか要約しています。