C++: nested class of a template class

Vahagn picture Vahagn · Nov 3, 2010 · Viewed 17.6k times · Source

Consider the following code:

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;
}

So here gcc-4.1.2 requires the template argument of f to be explicitly specified. Is this meet the standard? Does the newer versions of GCC have this issue fixed? How can I avoid explicitly specifying int while calling f?

Update: Here is a workaround.

#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;
}

However, I still can't see why call f( x ); is invalid. Can you refer to some point in the standard which says such call should be invalid? Can you bring an example where such call is ambiguous?

Answer

James McNellis picture James McNellis · Nov 3, 2010
typename A<T>::B

Here, T is in a nondeduced context, which means that T cannot be deduced from the function argument.

The problem is that in the general case, there is a potentially infinite number of possible types T that could match. Consider, for example, if instead of struct B { }; you had typedef int B;.