奇怪的行为

Strange behavior?

本文关键字:      更新时间:2023-10-16

可能重复:
我必须把"template"answers"typename"关键字放在哪里以及为什么?

几周前,我(不得不:(成为了一名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_cppexamplesgyakorlas_1.cpp   25
Error   2   error C2143: syntax error : missing ';' before '&'  d:learn_cppexamplesgyakorlas_vizsgagyakorlas_1.cpp  25
(both of them twice)

我对此一无所知,我认为模板可能有问题,因为如果我将SameCounter创建为一个普通类,那就完全可以了。谢谢你的帮助。

这应该会对您有所帮助:

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可能意味着不同的东西(类型名称,但也可以是静态成员…(,这取决于您传递的T

这就是为什么在模板中,有时你需要明确你的意图,并表明你实际上的意思是"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() {

我在下面宣布了您的类。有几点值得一提:

  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(,内部typedef会派上用场,并且它们可以避免重复键入嵌套typedef的typename
  • auto(C++11关键字(可以限制键入复杂的迭代器类型
  • 按值返回迭代器是惯用方法
  • begin((/end((的常量正确性
  • 重载用于非常量迭代器的begin((/end((,还提供cbegin((/cend((

通常情况下,最好使用与正在包装的函数(本例中为map的begin((/end(((相同的接口(constness,返回值(。

相关文章:
  • 没有找到相关文章