2008-08-19

Concept : Associated typeの不思議さ

associated typeは実に不思議だ。大抵は関数の戻り値の型を表すのに使われる。(14.9.1.2.2)。どうも、ネストされた型として使えるようだ。

auto concept Foo < typename T >
{
    requires std::CopyConstructible< T > ;
    typename type ;
    type T::func() ;
}

template < typename T > requires Foo< T >
void f( T x )
{
    x.func() ;
    // T::typeが使える。
    std::cout << typeid(typename T::type).name() << std::endl ;
}

struct Bar
{
    Bar func(){ return Bar() ; }
} ;


int main()
{
    f(Bar()) ;
}

しかし、以下のコードはコンパイルできない。

auto concept Foo < typename T >
{
    requires std::CopyConstructible< T > ;
    typename type ;
}

template < typename T > requires Foo< T >
void f( T x )
{
    std::cout << typeid(typename T::type).name() << std::endl ;
}

struct Bar
{
    typedef Bar type ;
} ;

int main()
{
    f(Bar()) ;
}

もし、associated typeで、テンプレートパラメーターのネストされた同名の型を使いたい場合は、default valueを使うことで実現できる。

auto concept Foo < typename T >
{
    requires std::CopyConstructible< T > ;
    typename type = T::type ;
}

なお、concept_mapで別名を割り当てることも可能だ。例えば、Bar::typeではなく、Bar::typoだったとしても、concept_mapを使えば、ご覧の通り。

struct Bar
{
    typedef Bar typo ;// おおっと!
} ;

concept_map Foo< Bar >
{
    typedef Bar::typo type ;// おkおk
}

そういえば、今までクラス内部でネストされたtypedefをなんと言うのか分からず、いろんな表現を使っていたが、規格用語としては、Nested type names(9.9)というらしい。そのまんまだ。

No comments: