C ++:模板类的嵌套类

时间:2010-11-03 22:29:17

标签: c++ templates gcc nested-class gcc4

请考虑以下代码:

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是否修复了此问题?如何在调用int时明确指定f

更新 这是一种解决方法。

#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 );无效。你能否参考标准中的某些观点,说这种呼叫应该是无效的?你能举出一个这样的电话不明确的例子吗?

4 个答案:

答案 0 :(得分:10)

typename A<T>::B

这里,T处于非弱化上下文中,这意味着无法从函数参数中推导出T

问题在于,在一般情况下,可能有无数种可能匹配的T类型。例如,考虑是否struct B { };代替typedef int B;

答案 1 :(得分:4)

  

如何在调用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 */ 
}

答案 2 :(得分:0)

  

如何避免明确指定   int调用f?

您需要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)。 e.g。

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)

答案 3 :(得分:0)

跟进“更新”中的问题,这里的情况是f的调用不明确(如果允许的话):

// Definitions of generic "struct A", as well as "f()", are the same as above

// But additionally, consider a specialized "struct A", defined as follows:

template <>
struct A<double>
{
    typedef A<int>::B B;
}

// Now consider the call to "f", similarly to before:

int main()
{
    // Possibility 1 for argument to "f()"
    // A<int>::B x;

    // Possibility 2 for argument to "f()": Use the specialized version of "struct A"
    A<double>::B x;

    f(x); // which value to deduce for type T?  Could be "int" or "double"
}

注意一组模糊的潜在实例化函数ff<int>()f<double>都会成功调用f()