为啥不能编译这个 C++ 模板代码?

Posted

技术标签:

【中文标题】为啥不能编译这个 C++ 模板代码?【英文标题】:Why can't this C++ template code be compiled?为什么不能编译这个 C++ 模板代码? 【发布时间】:2010-09-04 15:39:50 【问题描述】:

这是从The C++ Programming Language 第 17 章复制的一些示例代码,如下所示。当我用 Visual Studio 2008 编译它时,它一直给我这个错误: warning C4346: 'HashMap<Key,T,H,EQ,A>::mapped_type' : dependent name is not a type 1> prefix with 'typename' to indicate a type

有人对此有任何想法吗? 提前致谢!

#include <vector>
#include <map>
using std::vector;
using std::pair;
using std::iterator;

template<class Key, class T, class H= Hash<Key>, class EQ = equal_to<Key>, class A = allocator<pair<const Key, T>>>
class HashMap
public:
    typedef Key key_type;
    typedef T mapped_type;
    typedef pair<const Key, T> value_type;
    typedef typename A::size_type size_type;
    typedef H Hasher;
    typedef EQ key_equal;

    HashMap(const T& dv=T(), size_type n = 101, const H& hf = H(), const EQ& = EQ()):
            :default_value(dv), b(n), no_of_erased(0), hash(hf), eq(e)
        set_load();
        v.reserve(max_load*b.size());
    
    template<class In> HashMap(In first, In last,
        const T& dv=T(), size_type n=101, const H& hf=H(), const EQ& = EQ());

    void set_load(float m=0.7, float g=1.6)
        max_load = m;
        grow = g;
    
    mapped_type& operator[](const key_type& k);

    void resize(size_type n);
    void erase(iterator position);
    size_type size() const  return v.size() - no_of_erased;
    size_type bucket_count() const  return b.size();
    Hasher hash_fun() const  return hash;
    key_equal key_eq() const  return eq;

private:
    struct Entry
        key_type key;
        mapped_type val;
        bool erased;
        Entry* next;
        Entry(key_type k, mapped_type v, Entry* n):
            key(k),val(v),erased(false),next(n) 
    ;

    vector<Entry> v;
    vector<Entry*> b;

    float max_load;
    float grow;
    size_type no_of_erased;
    Hasher hash;
    key_equal eq;

    const T default_value;

;


template<class Key, class T, class H=Hash<Key>, class EQ=equal_to<Key>, class A=allocator<pair<const Key,T>>> 
HashMap<Key,T,H,EQ,A>::mapped_type & HashMap<Key,T,H,EQ,A>::operator [](const HashMap<Key,T,H,EQ,A>::key_type& k)
    size_type i = hash(k)%b.size();

    for(Entry* p=b[i]; p; p=p->next)
        if(eq(k, p->key))
            if(p->erased)
                p->erased = false;
                no_of_erased--;
                return p->val=default_value;
            
            return p->val;
        
    

    if(size_type(b.size()*max_load) <= v.size())
        resize(b.size()*grow);
        return operator[](k);
    

    v.push_back(Entry(k,default_value,b[i]));
    b[i] = &v.back();

    return b[i]->val;


template<class Key, class T, class H=Hash<Key>, class EQ=equal_to<Key>, class A=allocator<pair<const Key,T>>> 
void HashMap<Key,T,H,EQ,A>::resize(size_type s)
    size_type i = v.size();
    while(no_of_erased)
        if(v[--i].erased)
            v.erase(&v[i]);
            --no_of_erased;
        
    

    if(s<=b.size())
        return;
    b.resize(s);
    fill(b.begin(),b.end(),0);
    v.reserve(s*max_load);

    for(size_type i=0;i<v.size(); i++)
        size_type ii = hash(v[i].key)%b.size();
        v[i].next = b[ii];
        b[ii] = &v[i];
    


template<class Key, class T, class H=Hash<Key>, class EQ=equal_to<Key>, class A=allocator<pair<const Key,T>>>
void HashMap<Key,T,H,EQ,A>::erase(iterator p)
        if(p->erased == false) no_of_erased++;
        p->erased = true;



int main()
    return 0;

【问题讨论】:

为什么投反对票?如果著名书籍中的示例给出了来自知名编译器的警告,那么对于学习者来说,这似乎是一个很好的问题。 @ArtB:downvote 链接说“这个问题没有显示任何研究工作”。至少为此,因为错误清楚地说明了如何解决它。如果 OP 想知道为什么需要这样做,那么表示“尚不清楚”的 downvote 链接部分匹配。 @PlasmaHH 但是如果你是初学者,做研究真的很难。他们从“C++ 编程语言”中获取代码的事实已经表明他们正在进行研究。当一个问题是入门级的或用户是初学者时,很难进行有意义的研究。这与发布约 300 行代码并说“这里的东西坏了,帮我修好”不同 @ArtB:对我来说,它是“这是代码,它不能编译,我懒得看错误信息,你帮我做”。 【参考方案1】:

改变

HashMap<Key,T,H,EQ,A>::mapped_type & HashMap<Key,T,H,EQ,A>::operator []

typename HashMap<Key,T,H,EQ,A>::mapped_type & HashMap<Key,T,H,EQ,A>::operator []

正如您的错误已经暗示的那样。编译器无法自行推断mapped_type 是类模板中的typedef

【讨论】:

彼得,非常感谢您的回答!添加'typename'后它真的有效。但是还有另一个错误:错误C4519:默认模板参数只允许在类模板上似乎函数定义不能使用这样的模板参数:template, class EQ =equal_to, class A=allocator>> typename HashMap::mapped_type & HashMap: :operator [](const typename HashMap::key_type & k) 你有什么解决办法吗?再次感谢您! 好的,我明白了。谢谢提醒。感谢 Pieter,我已经解决了。

以上是关于为啥不能编译这个 C++ 模板代码?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 唯一指针;为啥这个示例代码会出现编译错误?错误代码太长了,我无法指定

为啥我的由 boost.python 和 c++ 头文件编译的 .so 文件失败了?

为啥编译器不能通过逗号运算符扩展可变参数模板的参数?

为啥这段代码不能在 Visual Studio 2010 中编译和运行?

为啥这个私有模板函数会编译? -> 编译器错误 VS 2009

为啥最简单的C++代码编译不出来?