web-dev-qa-db-ja.com

「fun」と「&fun」のタイプの違いは?

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;

両方のアサーションが成功し、両方の式が同じタイプであることを示唆します。ただし、typeidsは異なる結果を返します。

FvvE
PFvvE

何故ですか?

30
NPS

関数の引数から推測されるT型に適用されるため、両方のアサーションが成功します。どちらの場合も、関数は関数へのポインターに減衰するため、関数へのポインターとして推定されます。ただし、型を直接受け入れるようにアサーションを書き換えると、最初の型は失敗します。

static_assert(is_same<void(*)(), decltype(fun)>::value);
static_assert(is_same<void(*)(), decltype(&fun)>::value);

オンラインコンパイラ

28
VTT

fun&funは、 関数からポインターへの変換 のために同じ型を参照します。これはcheck<void(*)()>(fun);で実行されます。しかし、 typeid は例外です。

(エンファシス鉱山)

左辺値から右辺値、配列からポインター、または関数からポインターへの変換は実行されません

そして、ポインター変換への関数がcheck<void(*)()>(fun);に対して実行される理由は、 テンプレート引数の推定

控除が始まる前に、[〜#〜] p [〜#〜]および[〜#に対する次の調整〜] a [〜#〜]が作成されます。

1)[〜#〜] p [〜#〜]が参照型ではない場合、

  • if[〜#〜] a [〜#〜]は配列型、...;
  • それ以外の場合、[〜#〜] a [〜#〜]が関数タイプの場合、[〜#〜 ] a [〜#〜]は、関数からポインターへの変換から取得したポインター型に置き換えられます。

check()は値によってパラメーターを取得し、関数からポインターへの変換が実行され、Tの推定タイプも関数ポインターになります。つまり、void(*)()です。

17
songyuanyao

関数名を式として使用すると、それ自体へのポインターにdecaysします。したがって、fun&funと同じになります。

typeidに関しては、 このリファレンス から:

左辺値から右辺値、配列からポインター、または関数からポインター変換は実行されません。

[エンファシス鉱山]