Предлагать типы шаблонов подкласса в шаблоне - PullRequest
3 голосов
/ 12 июня 2011

У меня есть класс, производный от шаблонного класса:

template <typename A,typename B>
class TemplatedClass {

};

class Hello : public TemplatedClass<int,float>
{

};

Теперь я хочу создать шаблонный класс, который будет выводить типы int, float из Hello.
Я думал, что смогу сделать что-то подобное, но это не сработает:

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

Как я могу это сделать?

Edit:

Я хочу передать класс Hello , и шаблон должен вывести типы, используемые его подклассом TemplatedClass .

Итак, когда я создаю класс Check<Hello>, он получает типы int и float

Я не могу действительно изменить TemplatedClass, чтобы включить typedefs (это из внешнего .lib)

Edit:

Я изменил шаблон для использования Класс , но я получаю эту ошибку:
ошибка C3200: «Hello»: недопустимый аргумент шаблона для параметра шаблона «C», ожидается шаблон класса

Ответы [ 5 ]

3 голосов
/ 12 июня 2011

Сначала измените значение typename на class, §14.1 [temp.param] p1:

параметр типа:

  • класс идентификатор opt
  • класс идентификатор opt = идентификатор типа
  • имя типа идентификатор opt
  • имя типа идентификатор opt = идентификатор типа
  • шаблон <<em>список параметров шаблона > класс идентификатор опт
  • шаблон <<em> список параметров шаблона > class идентификатор opt = id-выражение

Далее выполните частичную специализацию:

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!
3 голосов
/ 12 июня 2011

Вы можете сделать что-то вроде этого:

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 голос
/ 12 июня 2011

То, что вы хотите, невозможно в общем случае - что если Hello получено из TemplatedClass дважды?

Это, однако, довольно просто сделать, даже ненавязчиво, в 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 вы все равно можете получить параметры внутри метода, но не можете получить к ним доступ снаружи, если не вставите специальные определения типов.

1 голос
/ 12 июня 2011

Я думаю, что вы можете сделать это, создав шаблонный класс для 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 (используя шаблоны как инструмент для простого переноса типов).

1 голос
/ 12 июня 2011

Попробуйте что-то вроде:

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
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...