可能重复:
Where and why do I have to put the “template” and “typename” keywords?
我已经(不得不:)几周前成为了一名C ++开发人员(我以前有过一些经验,但不是太多,我更喜欢Java),试图学习所有重要的东西,并且开发得像我可以。如果我的问题完全愚蠢,那么请原谅。我有一个简单的示例模板类的问题:
template<typename T>
class SameCounter {
private:
map<T,int> counted;
public:
SameCounter(list<T> setup) {
for(list<T>::iterator it = setup.begin(); it != setup.end(); it++) {
counted[*it]++;
}
}
map<T,int>::const_iterator& begin() { // line 25
return counted.begin();
}
map<T,int>::const_iterator& end() {
return counted.end();
}
};
...
// using the class
Reader rdr;
rdr.Read();
SameCounter<char> sc(rdr.GetData());
我在编译时遇到一些错误:
Error 3 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int d:\learn_cpp\examples\gyakorlas_1.cpp 25
Error 2 error C2143: syntax error : missing ';' before '&' d:\learn_cpp\examples\gyakorlas_vizsga\gyakorlas_1.cpp 25
(both of them twice)
我对它没有任何线索,也许我假设的模板有问题,因为如果我创建SameCounter作为普通类,那就完全没问题了。谢谢你的帮助。
答案 0 :(得分:9)
这可以帮到你:
typename map<T,int>::const_iterator& begin() {
return counted.begin();
}
typename map<T,int>::const_iterator& end() {
return counted.end();
}
C ++模板很棘手。 T是一个模板参数,map<T, int>::const_iterator
可能意味着不同的东西(类型名称,但是 - 比如静态成员......),这取决于你传递的是什么。
这就是为什么在模板中有时你需要明确你的意图,并表明你实际上是指“const_iterator
是一种类型,我想要它的引用”。关键字'typename'允许这样做。
请参阅:http://pages.cs.wisc.edu/~driscoll/typename.html
为了使您的代码更简单并且避免减少对typename
的需求,您可以从以下开始:
private:
typedef std::map<T, int> MapType;
MapType counted;
然后继续
typename MapType::const_iterator &begin() {
不幸的是,这个typename
仍然需要在这里,你需要为每个依赖类型进一步typedef typename
将其从进一步的声明中删除(参见@ rhalbersma 的回答)。
关注@ rhalbersma 的评论,让我也强调一下你应该按值修改这些迭代器。返回对临时值的引用会导致未定义的行为,因为对象超出了范围,最终会出现“悬空引用”。
所以吧:
typename MapType::const_iterator begin() {
答案 1 :(得分:2)
我在下面注释了你的课程。有几点值得一提:
template<typename T>
class SameCounter
{
private:
typedef map<T,int> MapType; // typedef here to keep specific container in a single place
typedef typename MapType::const_iterator const_iterator; // to avoid retyping "typename"
typedef typename MapType::iterator iterator; // to avoid retyping typename
MapType counted;
public:
SameCounter(list<T> setup) {
// auto here to avoid complicated expression
for(auto it = setup.begin(); it != setup.end(); it++) {
counted[*it]++;
}
}
// by value instead of by reference, mark as const member
const_iterator begin() const {
return counted.begin();
}
// by value instead of by reference, mark as const member
const_iterator end() const {
return counted.end();
}
// probably best to also forward cbegin()/cend() and non-const begin() / end()
};
map
更改为另一个容器(例如unorderd_map
),它会派上用场,并避免重复输入typename
嵌套的typedef。一般情况下,最好使用与包装函数相同的接口(constness,返回值)(在本例中为map的begin()/ end())。