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

use*_*413 11 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_ */
Run Code Online (Sandbox Code Playgroud)

TEST.CPP

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

int main(){   
    Stack<int, std::vector<int> > stack;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

Stack<int, std::vector<int> > stack;
Run Code Online (Sandbox Code Playgroud)

错误:

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

?
Run Code Online (Sandbox Code Playgroud)

Xeo*_*Xeo 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;
Run Code Online (Sandbox Code Playgroud)

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

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

// usage:
Stack<int, std::vector<int> > s;
Run Code Online (Sandbox Code Playgroud)

要确保底层类型具有相同的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;
  // ...
};
Run Code Online (Sandbox Code Playgroud)

这样做是因为,如果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;
  // ...
};
Run Code Online (Sandbox Code Playgroud)

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

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

// usage:
Stack<int> s;
Run Code Online (Sandbox Code Playgroud)

在这一点上,您可以使用std::stack哪个正是这样做(尽管它std::deque用作底层类型).:)