Сокращение количества аргументов шаблона для класса - PullRequest
0 голосов
/ 07 октября 2010

У меня есть метод и два класса, определенные следующим образом:

template<template<class X> class T>
void doSomething()
{  
    T<int> x;
}
template <class T>
class ClassWithOneArg
{
    T t;
};

template <class T1, class T2>
class ClassWithTwoArgs
{
    T1 t1;
    T2 t2;
};

Теперь я могу

doSomething<ClassWithOneArg>();

, но я не могу

doSomething<ClassWithTwoArgs>();

Однако яхотелось бы передать ClassWithTwoArgs в doSomething, где T2 = double.

Единственный найденный мной метод - это создать

template <class T1>
class ClassWithTwoArgs_Child
    : public ClassWithTwoArgs<T1, double>
{
};

, а затем

doSomething<ClassWithTwoArgs_Child>();

Это работает, но в моем конкретном случае все классы требуют аргумента конструктора, и поэтому я должен создать конструктор с этим аргументом также в классе _Child и передать его в базу, которой я действительно хочу избежать.

У вас есть идея, как это сделать?

Большое спасибо!

Ответы [ 5 ]

3 голосов
/ 07 октября 2010

Обращение - это решение. Вместо параметра шаблона шаблона вы передаете «мета-функцию» - функцию, которая отображает один тип на другой в форме структуры с вложенным шаблоном класса:

struct mf1 {
  template<class Arg1>
  struct eval {
    typedef ClassTemplateWithOneArg<Arg1> type;
  };
};

template<class Arg2>
struct mf2 {
  template<class Arg1>
  struct eval {
    typedef ClassTemplateWithTwoArgs<Arg1,Arg2> type;
  };
};

template<class MetaFunc>
void do_something()
{
  typedef typename MetaFunc::template eval<int>::type clazztype;
  clazztype x;
}

void foo() {
  do_something<mf1>();
  do_something<mf2<double> >();
}

В C ++ 0x это может быть уменьшено до «шаблона typedef»:

template<class Arg1>
using NewClassTemplate = ClassTemplateWithTwoArgs<Arg1,double>;

, который позволяет передавать NewClassTemplate в качестве аргумента шаблона шаблона, который также принимает только один параметр шаблона.

1 голос
/ 07 октября 2010

Если вы хотите объявить экземпляры шаблона одного и того же класса с другим типом для первого параметра шаблона, возможно, существует версия кода посетителя, которая не требует изменения исходных классов.

template <class T, class NewFirstArg>
struct rebind_1st;

template <template <class> class T, class Arg1, class NewFirstArg>
struct rebind_1st<T<Arg1>, NewFirstArg>
{
    typedef T<NewFirstArg> type;
};

template <template <class, class> class T, class Arg1, class Arg2, class NewFirstArg>
struct rebind_1st<T<Arg1, Arg2>, NewFirstArg>
{
    typedef T<NewFirstArg, Arg2> type;
};

template <class T>
void foo()
{
    typename rebind_1st<T, int>::type x;
    (void)x;
}

template <class T>
struct One{};

template <class T1, class T2>
struct Two{};

int main()
{
    foo<One<char> >();
    foo<Two<char, double> >();
}
1 голос
/ 07 октября 2010

Кажется, что то, что вам нужно, похоже на повторное связывание распределителей (учитывая распределитель, контейнеры должны иметь возможность создавать распределитель для другого типа - например, std::list<int> может потребоваться allocator<list_node<int> > из allocator<int>.

Однако для этого необходимо изменить шаблоны классов.

template<class T>
void doSomething(const T&)
{  
    typename T::template rebind_1st<int>::type x;
}

template <class T>
class ClassWithOneArg
{
    T t;
public:
    template <class U>
    struct rebind_1st { typedef ClassWithOneArg<U> type; };
};

template <class T1, class T2>
class ClassWithTwoArgs
{
    T1 t1;
    T2 t2;
public:
    template <class U>
    struct rebind_1st { typedef ClassWithTwoArgs<U, T2> type; };
};

int main()
{
    doSomething(ClassWithOneArg<char>());
    doSomething(ClassWithTwoArgs<char, double>() );
}
1 голос
/ 07 октября 2010

Универсального решения не существует.Ваша лучшая ставка

template<class T> 
void doSomething() 
{   
    T x; 
} 
template <class T> 
class ClassWithOneArg 
{ 
    T t; 
}; 

template <class T1, class T2 = double> 
class ClassWithTwoArgs 
{ 
    T1 t1; 
    T2 t2; 
}; 

int main(){
    doSomething<ClassWithOneArg<int>>(); 
    doSomething<ClassWithTwoArgs<int, double> >();
}
0 голосов
/ 07 октября 2010

Это работает с MSVC:

template<class T>
void doSomething()
{  
    T x;
}

// class definitions omitted...

void test() {
    doSomething<ClassWithOneArg<int> >();
    doSomething<ClassWIthTwoArgs<int, double> >();
}

Я не до конца понимаю, почему вы хотите определить первый параметр вашего шаблона шаблона как int внутри doSomething.Выглядит как «запах шаблона» для меня, так как doSomething должен много знать о параметре шаблона шаблона.

Не было бы чище назвать doSomething так, как я предложил?(Но, очевидно, я не знаю контекст ваших звонков).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...