基于pp. 179
上的示例template<template<typename T, typename A> class C, typename T, typename A>
^^^^^^^^^^^^^^^^^^^^^^
void erase(C<T, A>&c, const T& item)
{
c.erase(std::remove(c.begin(), c.end(), item), c.end());
}
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
{
list<int> lst;
lst.push_back(42);
erase(lst, 42);
}
如果我从typename T, typename A
函数签名中删除erase
,VS2010编译器会出现以下错误:
Error 1 error C2065: 'T' : undeclared identifier Error 2 error C2065: 'A' : undeclared identifier Error 3 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int Error 4 error C2143: syntax error : missing ',' before '&'
问题1 &GT;这些编译错误背后的原因是什么?
我们总是必须明确定义模板模板参数中使用的类型参数吗?
问题2 &GT;当我们调用以下行时,编译器如何推导出A
的类型?
erase(lst, 42)
编译器是否真的根据A
中定义的模板参数A的默认参数推断出类型list
?
请参阅list
template < class T, class Allocator = allocator<T> > class list;
类型A
是allocator<T>
?
答案 0 :(得分:8)
问题1
首先T
和A
是C
的参数,而不是erase()
模板的参数。因此,它们不可见,可见的是用^^^突出显示的第二个和第三个参数。请注意,第一个参数是不一个typename / class,它是一个类模板。类模板本身不是类型,只有它的实例化。
为了更好地了解第一个T
和A
如何不可见并且实际上没有扮演任何角色,您可以像这样重写它:
template<template<typename, typename> class C, typename T, typename A>
问题2
它可以推导A
,因为lst
传递为C<T, A>
,因此A
是lst
类型的类模板的第二个参数。
最后,您应该以不同的方式重写您的功能模板:
template <typename C>
void erase(C& c, const typename C::value_type& item)
{
c.erase(std::remove(c.begin(), c.end(), item), c.end());
}
这样,您不会限制C
模板参数的数量和含义。实际上,如果需要,此处C
可以是非模板化类型。
答案 1 :(得分:1)
如果删除这些,则A和T仅在C的上下文中已知,而不是在erase()模板的上下文中。