C ++模板模板(双模板?)

时间:2011-06-25 11:13:40

标签: c++ templates

我想构建一个Stack类,以便用户可以选择要用于实现Stack的容器。例如,List/Vector

部分代码:

stack.h

#ifndef STACK_H_
#define STACK_H_

template <typename T, template<typename T> class ContainerType>
class Stack{
    ContainerType<T> container;
public:
    Stack() : container(ContainerType<T>()){}

};

#endif /* STACK_H_ */

TEST.CPP

#include "stack.h"
#include <vector>

int main(){   
    Stack<int, std::vector<int> > stack;
    return 0;
}

好吧,它没有编译。我在网上得到了下一个错误:

Stack<int, std::vector<int> > stack;

错误:

expected a class template, got `std::vector<int, std::allocator<int> >' test.cpp

invalid type in declaration before ';' token test.cpp

type/value mismatch at argument 2 in template parameter 
list for `template<class T, template<class T> class ContainerType> 
class Stack' test.cpp

‪

4 个答案:

答案 0 :(得分:22)

首先,它是std::vector,而不是其他任何内容,因为vector位于std命名空间中,并且您要求模板模板参数,虽然std::vector<int>不再是模板。接下来,std::vector实际上需要两个模板参数,一个用于类型,另一个用于分配器:

template <
    typename T,
    template<typename, typename> class ContainerType,
    typename Alloc = std::allocator<T>
>
class Stack{
  ContainerType<T, Alloc> container;
  // ...
};

// usage:
Stack<int, std::vector> s;

现在,这只启用带有两个模板参数的容器作为基础类型,因此您最好使用标准做的事情:将其作为普通类型:

template <typename T, typename ContainerType>
class Stack{
  ContainerType container;
  // ...
};

// usage:
Stack<int, std::vector<int> > s;

要确保底层类型具有相同的T,您可以执行虚假的“静态断言”,或者如果您启用了C ++ 0x编译器,则可以执行实际的静态断言:

#include <tr1/type_traits> // C++03 us std::tr1::is_same
//#include <type_traits> // C++0x, use std::is_same

template <typename T, typename ContainerType>
class Stack{
  typedef typename ContainerType::value_type underlying_value_type;
  typedef char ERROR_different_value_type[
               std::tr1::is_same<T, underlying_value_type>::value ? 1 : -1
                                         ]
  ContainerType container;
  // ...
};

这是有效的,因为如果T与使用的容器的T不同,它将是typedef char ERROR_different_vale_type[-1],并且可能不存在负大小的数组,这会导致编译器错误。 :)现在,使用C ++ 0x,您只需static_assert

#include <tr1/type_traits> // C++03
//#include <type_traits> // C++0x

template <typename T, typename ContainerType>
class Stack{
  typedef typename ContainerType::value_type underlying_value_type;
  static_assert(std::tr1::is_same<T, underlying_value_type>::value,
    "Error: The type of the stack must be the same as the type of the container");
  ContainerType container;
  // ...
};

为方便起见,您现在可以为常见情况指定默认模板参数:

template <typename T, typename ContainerType = std::vector<T>>
class Stack{
  ContainerType container;
  // ...
};

// usage:
Stack<int> s;

此时你可以使用std::stack来完成这一点(尽管它使用std::deque作为基础类型)。 :)

答案 1 :(得分:2)

由于vector属于std命名空间,您必须对其进行限定。但除此之外,因为ContainerType是模板模板参数,您需要传递模板而不是最终类型:

Stack<int, std::vector > stack;

答案 2 :(得分:2)

最简单的方法是不使用模板模板参数,因为容器的arity存在问题。

相反,只需传递完整的容器类型即可。然后提取value_type(标准STL内部typedef)以获取值。

template <typename Container>
class Stack
{
public:
  typedef typename Container::value_type value_type;

private:
  Container _container;
}; // class Stack<Container>

然后,您可以简单地将其用作Stack< std::vector<int> >,并且它将包含int s。

答案 3 :(得分:1)

这一行:

     Stack<int, vector<int> > stack;

应该是:

  Stack<int, std::vector<int> > stack;

或者您可以在test.cpp前加上

 using namespace std;