【问题标题】:C++: nested class of a template classC++:模板类的嵌套类
【发布时间】:2011-05-04 18:46:57
【问题描述】:

考虑以下代码:

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 ); 无效。您能否参考标准中的某些点,即此类调用应该是无效的?你能举一个这样的叫法模棱两可的例子吗?

【问题讨论】:

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


    【解决方案1】:
    typename A<T>::B
    

    这里,T 处于非推导上下文中,这意味着不能从函数参数推导 T

    问题在于,在一般情况下,可能有无数种可能的类型T 可以匹配。例如,假设您使用typedef int B; 而不是struct B { };

    【讨论】:

    • 感谢您的回答。为什么不能从函数参数推导出T?您能否举一个例子,其中T 有两种类型,它们与f 的一个特定调用相匹配?你的意思是,对于A 的另一个专业化,它可能是另一个typedef int B; 而不是struct B {};?我不明白为什么在这种情况下f 的调用应该是模棱两可的。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      如何避免明确指定 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)。例如

      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)

      【讨论】:

      • 感谢您的回答。添加一个额外的参数对我不起作用,因为实际上我有重叠的运算符而不是f
      【解决方案4】:

      跟进“更新”中的问题,在这种情况下,对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&lt;int&gt;()f&lt;double&gt; 都会成功调用 f()

      【讨论】:

        猜你喜欢
        • 2018-11-08
        • 2017-02-05
        • 2015-07-29
        • 2018-04-22
        • 2019-02-25
        • 2018-02-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多