識別子 - インナークラス 使いどころ c++




C++:テンプレートクラスの入れ子クラス (3)

fの呼び出し中にintを明示的に指定しないようにするにはどうすればよいですか?

Bそのネストクラス型を宣言させるだけでよい

template < typename T >
struct A
{
    struct B { typedef A outer; };
};

それからあなたはそれを推測することができます。 以下は、外側のテンプレート、内側のtypedef、および戻り型を取ります。

template<template<typename> class Outer, typename D, typename R = void >
struct nesting { };

template<template<typename> class Outer, typename Arg, typename R>
struct nesting< Outer, Outer<Arg>, R > {
  typedef Arg arg1_type;
  typedef R type;
};

template < typename T >
typename nesting<A, typename T::outer>::type
f(T) { 
  /* nesting<A, typename T::outer>::arg1_type is A's T */ 
}

次のコードを見てください。

template < typename T >
struct A
{
    struct B { };
};

template < typename T >
void f( typename A<T>::B ) { }

int main()
{
    A<int>::B x;
    f( x );         // fails for gcc-4.1.2
    f<int>( x );    // passes
    return 0;
}

したがって、ここでgcc-4.1.2はfのテンプレート引数が明示的に指定されることを要求します。 これは規格を満たしていますか? GCCの新しいバージョンではこの問題は修正されていますか? f呼び出し中にintを明示的に指定しないようにするにはどうすればよいですか?

更新:これが回避策です。

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>

template < typename T >
struct A
{
    typedef T argument;
    struct B { typedef A outer; };
};

template < typename T >
void f( typename A<T>::B ) { }

template < typename Nested >
void g( Nested )
{   
    typedef typename Nested::outer::argument TT;
    BOOST_STATIC_ASSERT( (boost::is_same< typename A<TT>::B, Nested >::value) );
}

struct NN 
{
    typedef NN outer;
    typedef NN argument;
};

int main()
{
    A<int>::B x;
    NN y;
    g( x );  // Passes
    g( y );  // Fails as it should, note that this will pass if we remove the type check
    f( x );  // Fails as before

    return 0;
}

しかし、なぜf( x );呼ぶのか、まだわかりませんf( x ); 無効です。 そのような呼び出しは無効であるべきであると言う、標準の中のある点を参照できますか? そのような電話があいまいな例を挙げてください。


fの呼び出し中にintを明示的に指定しないようにするにはどうすればよいですか?

あなたはstruct Bから少し助けが必要です。

template < typename T >
struct A
{
    struct B 
    { 
        static T getType(); // no impl required 
    };
};

#define mytypeof(T) (true?0:T)

template < typename T, typename U >
void f( T t, U ) { } // U will be T of A<T>::B

次のように呼び出します。

f(x, mytypeof(x.getType()));

あるいは、fが呼び出す別の関数を導入することによってmytypeof(x.getType())抽象化して、元のf(x)を得ることもできます。 例えば

template < typename T, typename U >
void b( T t, U ) { } // U will be T of A<T>::B

template < typename T >
void f( T t )
{
    b(t, mytypeof(t));
}

あなたはそれからf(x)呼び出すことができます。


typename A<T>::B

ここで、 Tは演繹されていない文脈にあり、これはTが関数の引数から演繹され得ないことを意味します。

問題は、一般的なケースでは、一致する可能性のある潜在的に無限の数の可能な型Tあることです。 たとえば、 struct B { };代わりに あなたはtypedef int B;を持っていましたtypedef int B;





gcc4