在模板中推断子类模板类型

时间:2011-06-12 17:01:42

标签: c++ templates inheritance

我有一个派生自模板类的类:

template <typename A,typename B>
class TemplatedClass {

};

class Hello : public TemplatedClass<int,float>
{

};

现在,我想创建一个模板化的类,它将从Hello推断出 int,float 类型。
我以为我可以做这样的事情,但它不起作用:

template <template <typename A,typename B> class C>
class Check
{
    void Foo(A,B,C)
    {
        // A is int .. B is float .. C is Hello
    }
};



int _tmain(int argc, _TCHAR* argv[])
{
    Check<Hello> a;
}

我该怎么做?

编辑:

我想传递 Hello 类,并让模板推断其子类 TemplatedClass 使用的类型。

因此,当我创建一个类Check<Hello>时,它将获得类型int和float

我无法真正将TemplatedClass更改为包含typedef(它来自外部.lib)

修改

我已将模板更改为使用 Class ,但我收到此错误:
错误C3200:'Hello':模板参数'C'的模板参数无效,需要一个类模板

5 个答案:

答案 0 :(得分:3)

你可以这样做:

template <template <typename A,typename B> typename C>
class Check
{
     template<typename A, typename B>
     void Foo(A a, B b) {
        // C<A,B> would reconstruct the template type
     }
}

// use: 
Check<Hello> a;
a.Foo(true,1.f);

或者,这(你的意图并不完全清楚):

template <typename A,typename B>
class TemplatedClass {
   typedef A TypeA;
   typedef B TypeB;
};


template <typename C>
class Check
{

     void Foo(typename C::TypeA& a, typename C::TypeB&) {}
}

// use: 
Check<Hello<int,float> > a;
a.Foo(1,1.f);

答案 1 :(得分:3)

首先,将typename更改为class§14.1 [temp.param] p1

  

型参数:

     
      
  • class 标识符 opt
  •   
  • class 标识符 opt = type-id
  •   
  • typename 标识符 opt
  •   
  • typename 标识符 opt = type-id
  •   
  • template&lt; template-parameter-list &gt; 标识符 opt
  •   
  • template&lt; template-parameter-list &gt; 标识符 opt = id-expression
  •   

接下来,进行部分专业化:

template<class T>
class Check;

template< // not 'typename'   vvvvv
  template<typename,typename> class C,
  typename A, typename B
>
struct Check<C<A,B> >{
  // ...
};

但是,您仍然无法仅将Hello传递给模板,因为即使Hello派生自TemplatedClass,模板参数也不允许进行类型转换:

Check<Hello> c; // nope, 'Hello' is not a template

您可以将以下typedef添加到Hello类:

class Hello
  : TemplatedClass<int,float>
{
public:
  typedef TemplatedClass<int,float> base_type;
};

并做:

检查c; // 好 但是,C中的Check参数将为template TemplatedClass,而不是Hello。可悲的是,没有办法直接实现这一目标。一种解决方案是将派生类型作为额外的模板参数传递,或者只是将派生类型作为唯一参数传递,并在内部进行类型提取:

template<class T>
class CheckInternal;

template<
  template<typename,typename> class C,
  typename A, typename B
>
class CheckInternal<C<A,B> >{
  public:
     typedef A type_A;
     typedef B type_B;
};

template<class T>
class Check{
  typedef typename T::base_type T_base_type;
  typedef typename CheckInternal<T_base_type>::type_A type_A;
  typedef typename CheckInternal<T_base_type>::type_B type_B;

  void foo(type_A a, type_B b){
    // ...
  }
};

// usage:
C<Hello> c; // OK!

答案 2 :(得分:1)

尝试类似:

template <typename A,typename B>
class TemplatedClass {
public:    
    typedef A firstType;
    typedef B secondType;
};

class Hello : public TemplatedClass<int,float>
{
public:    
    typedef firstType Type1;
    typedef secondType Type2;
};

template <typename C>
class Check
{
    typedef typename C::Type1 A;
    typedef typename C::Type2 B;

    void Foo(A,B,C)
    {
        // A is int .. B is float .. C is Hello
    }
};

答案 3 :(得分:1)

我认为你可以通过为Hello创建一个模板化的类来实现它,然后输入定义它的特化。类似的东西:

template <typename A, typename B>
class HelloBase : public TemplatedClass<A, B>
{
public:    
    typedef A Type1;
    typedef B Type2;
};

typedef HelloBase<int, float> Hello;

template <typename C>
class Check
{
    typedef typename C::Type1 A;
    typedef typename C::Type2 B;

    void Foo(A,B,C)
    {
        // A is int .. B is float .. C is Hello
    }
};

...

Check<Hello> a;

所以TemplatedClass不需要改变,你可以将你要放入Hello的所有内容放入HelloBase中(使用模板作为简单携带类型的工具)。

答案 4 :(得分:1)

在一般情况下,您想要的是什么 - 如果HelloTemplatedClass派生两次会怎样?

然而,在C ++ 0x下,即使是非侵入式的,也是相当简单的。

template<typename A, typename B> struct retval {
    typedef A first;
    typedef B second;
};
template<typename one, typename two> one first(const TemplatedClass<one, two>& ref);
template<typename one, typename two> two second(const TemplatedClass<one, two>& ref);
template<typename T> class Check {
    typedef decltype(first(*static_cast<T*>(nullptr))) first;
    typedef decltype(second(*static_cast<T*>(nullptr))) second;
};

在C ++ 03中,你仍然可以在方法中获取参数,但不能在外部访问它们,除非你插入特殊的typedef。