const な右辺値に対する参照テンプレートパラメータの型推論と一時オブジェクトの束縛

つい最近知ってちょっと衝撃を受けたことについて.
非const参照パラメータが指定されている関数の項に右辺値(リテラルもしくは関数から返される一時オブジェクト)を指定できないのは有名.

void f( int &i )
{
  .....
}

int g()
{
  return 1;
}

int main()
{
  f( g() ); // ダメ. C++ の言語規格では認められていない
}

これは非constなテンプレートパラメータが指定された関数の項でも同じ.

template< class T >
void f( T &i )
{
  .....
}

int g()
{
  return 1;
}

int main()
{
  f( g() ); // 同じくダメ.
}

これは比較的良く知られている(のか?)規格で,別にいまさらこれに驚いたわけじゃない.
ところが右辺値の型が const 修飾されていると,それがこの非 const な参照テンプレートパラメータを指定された項で受けられることにいまさら気が付いた.

template< class T >
void f( T &i )
{
  .....
}

int const g() // 戻り値が const 修飾されていることに注意
{
  return 1;
}

int main()
{
  f( g() ); // O.K. f のテンプレートパラメータ T が int const と
            // 推論されるので f が一時オブジェクトを受けられる.
}

これに驚いた.
Boost.Lambda において生成される(一時オブジェクトである)ラムダ式オブジェクトに対する The forwarding problem をどう解決しているのか不思議といえば不思議だったのだけれど,なるほど,どうりでわざわざラムダ式オブジェクトのオブジェクトジェネレータの戻り値を const にしているわけですにゃ〜.ようやくあの Boost.Lambda の実装の const 修飾の意味を理解したつもりになった.そんにゃ冬の日の夜.