C++:模板类的嵌套类

15

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

因此,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 ); 是无效的。你能否参考一些标准中说明这样的调用应该是无效的点?你能否提供一个这样的调用会导致歧义的例子吗?

4个回答

13
typename A<T>::B

在这里,T处于未推导的上下文中,这意味着T无法从函数参数中推导出来。
问题在于,在一般情况下,可能存在无限多个可能匹配的类型T。例如,考虑如果你有typedef int B;而不是struct B { };

3
谢谢你的回答。为什么无法从函数参数中推断出 T 的类型?你能举个例子,在某个特定的 f 调用中有两种类型与 T 匹配吗?你的意思是,对于 A 的另一个特化,它可能会使用另一种 typedef int B; 而不是 struct B {}; 吗?我看不出在这种情况下为什么调用 f 会产生歧义。 - Vahagn

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 */ 
}

0
如何在调用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)


1
谢谢你的回答。对我来说添加额外的参数行不通,因为实际上我有重载运算符而不是 f - Vahagn

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

请注意潜在的实例化函数对:无论是()>还是>,都将成功调用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接