减少类的模板参数数量

时间:2010-10-07 12:30:55

标签: c++ templates

我有一个方法和两个定义如下的类:

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 个答案:

答案 0 :(得分:3)

间接是一种解决方案。您可以传递一个“元函数”而不是模板模板参数,该元函数将一种类型映射到具有嵌套类模板的结构形式的另一种类型:

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中,这可以简化为“template typedef”:

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

允许您将NewClassTemplate作为模板模板参数传递,该参数也只接受一个模板参数。

答案 1 :(得分:1)

没有通用解决方案。你最好的选择是

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

答案 2 :(得分:1)

看起来你所追求的与分配器的重新绑定类似(给定一个分配器,容器需要能够为不同类型生成分配器 - 例如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>() );
}

答案 3 :(得分:1)

假设您希望为第一个模板参数声明具有不同类型的同一类的模板实例化,则可能会显示访问者代码的版本,而不需要修改原始类。

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

答案 4 :(得分:0)

这适用于MSVC:

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

// class definitions omitted...

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

我不完全理解为什么要在int内将模板模板参数的第一个参数定义为doSomething。看起来像是一个“模板味道”,因为doSomething必须对其模板模板参数有很多了解。

以我提议的方式致电doSomething会不会更清晰? (但显然我不知道你的电话的背景。)