式fun
および&fun
は同じタイプですか?
次のコードを検討してください。
template <typename Check, typename T>
void check(T)
{
static_assert(is_same<Check, T>::value);
}
void fun()
{}
check<void(*)()>(fun);
check<void(*)()>(&fun);
cout << typeid(fun).name() << endl;
cout << typeid(&fun).name() << endl;
両方のアサーションが成功し、両方の式が同じタイプであることを示唆します。ただし、typeid
sは異なる結果を返します。
FvvE
PFvvE
何故ですか?
関数の引数から推測されるT
型に適用されるため、両方のアサーションが成功します。どちらの場合も、関数は関数へのポインターに減衰するため、関数へのポインターとして推定されます。ただし、型を直接受け入れるようにアサーションを書き換えると、最初の型は失敗します。
static_assert(is_same<void(*)(), decltype(fun)>::value);
static_assert(is_same<void(*)(), decltype(&fun)>::value);
fun
と&fun
は、 関数からポインターへの変換 のために同じ型を参照します。これはcheck<void(*)()>(fun);
で実行されます。しかし、 typeid
は例外です。
(エンファシス鉱山)
左辺値から右辺値、配列からポインター、または関数からポインターへの変換は実行されません。
そして、ポインター変換への関数がcheck<void(*)()>(fun);
に対して実行される理由は、 テンプレート引数の推定
控除が始まる前に、[〜#〜] p [〜#〜]および[〜#に対する次の調整〜] a [〜#〜]が作成されます。
1)[〜#〜] p [〜#〜]が参照型ではない場合、
- if[〜#〜] a [〜#〜]は配列型、...;
- それ以外の場合、[〜#〜] a [〜#〜]が関数タイプの場合、[〜#〜 ] a [〜#〜]は、関数からポインターへの変換から取得したポインター型に置き換えられます。
check()
は値によってパラメーターを取得し、関数からポインターへの変換が実行され、T
の推定タイプも関数ポインターになります。つまり、void(*)()
です。
関数名を式として使用すると、それ自体へのポインターにdecaysします。したがって、fun
は&fun
と同じになります。
typeid
に関しては、 このリファレンス から:
左辺値から右辺値、配列からポインター、または関数からポインター変換は実行されません。
[エンファシス鉱山]