c++ - 为什么我需要在以下示例中的 block_cache.h 之前包含 block_cache_key.h 和 block.h?

标签 c++ unordered-map

通常我们会使用标准类型作为 std::unordered_map<key, value> 的键和值.但现在我需要自定义我自己的键和值类。

键类在block_cache_key.h 中定义如下:

#ifndef BLOCK_CACHE_KEY_H_
#define BLOCK_CACHE_KEY_H_

#include <functional>

namespace wcg{
class BlockCacheKey{
public:
    BlockCacheKey(const std::string &name, int64_t offset) : name_(name), offset_(offset) {}

    bool operator==(const BlockCacheKey &other) const{
        return offset_ == other.offset_ && name_ == other.name_;
    }

    const std::string &name() const{
        return name_;
    }

    const int64_t offset() const{
        return offset_;
    }

    std::string to_string() const{
        return name_ + "_" + std::to_string(offset_);
    }

private:
    std::string name_;
    int64_t offset_;
};
}

namespace std{
    template <>
    class hash<wcg::BlockCacheKey>{
    public:
        size_t operator()(const wcg::BlockCacheKey &key) const{
            return std::hash<std::string>()(key.name()) ^ (std::hash<int64_t>()(key.offset()));
        }
    };
}

#endif

值类在 block.h 中定义如下:

#ifndef BLOCK_H_
#define BLOCK_H_

namespace wcg{
class Block{
public:
    Block() {}
};
}

#endif

以及使用 std::unorded_map 的类在 block_cache.h 中定义如下:

#ifndef BLOCK_CACHE_H_
#define BLOCK_CACHE_H_

#include <iostream>
#include <memory>
#include <unordered_map>

namespace wcg{

class BlockCacheKey;
class Block;

class BlockCache{
public:
    BlockCache() : count_(0) {
        std::cout << "initial stats: " << to_string() << std::endl;
    }

    ~BlockCache(){
        std::cout << "final stats: " << to_string() << std::endl;
    }

    void CacheBlock(const BlockCacheKey &key, std::shared_ptr<Block> block){
        std::cout << "cache put: " << key.to_string() << std::endl;
        map_[key] = block;
        count_++;
    }

    std::shared_ptr<Block> GetBlock(const BlockCacheKey &key){
        auto pos = map_.find(key);
        if(pos != map_.end()){
            std::cout << "cache get: " << key.to_string() << std::endl;
            return pos->second;
        }
        return nullptr;
    }

    std::string to_string() const{
        return "block count: " + std::to_string(count_);
    }

private:
    std::unordered_map<BlockCacheKey, std::shared_ptr<Block>> map_;
    int count_;
};
}

#endif

主要功能定义在main.cpp中如下:

#include <memory>

#include "block_cache_key.h"
#include "block.h"
#include "block_cache.h"

// g++ -std=c++11 -g -Wall main.cpp

int main(int argc, char* argv[]){
    wcg::BlockCache bc;
    return 0;
}

#include "block_cache.h"终于,编译OK了。但是当#include "block_cache.h"#include "block_cache_key.h" 之前和 #include "block.h" ,编译会失败,错误信息非常难看,很难理解。

我已经知道的,std::unordered_map是一个模板。 GCC在编译时,会先对include部分进行预处理,即全部展开。 这给我的印象是包含顺序不是问题。

最后要注意的是,我不想包括 block_cache_key.hblock.hblock_cache.h

部分编译错误信息: (完整的错误消息在 https://paste.ubuntu.com/p/VyrWKCTG4q/ 中)

In file included from /usr/include/c++/7/bits/hashtable.h:35:0,
                 from /usr/include/c++/7/unordered_map:47,
                 from block_cache.h:13,
                 from main.cpp:5:
/usr/include/c++/7/bits/hashtable_policy.h: In instantiation of 'struct std::__detail::__is_noexcept_hash<wcg::BlockCacheKey, std::hash<wcg::BlockCacheKey> >':
/usr/include/c++/7/type_traits:143:12:   required from 'struct std::__and_<std::__is_fast_hash<std::hash<wcg::BlockCacheKey> >, std::__detail::__is_noexcept_hash<wcg::BlockCacheKey, std::hash<wcg::BlockCacheKey> > >'
/usr/include/c++/7/type_traits:154:31:   required from 'struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<wcg::BlockCacheKey> >, std::__detail::__is_noexcept_hash<wcg::BlockCacheKey, std::hash<wcg::BlockCacheKey> > > >'
/usr/include/c++/7/bits/unordered_map.h:103:66:   required from 'class std::unordered_map<wcg::BlockCacheKey, std::shared_ptr<wcg::Block> >'
block_cache.h:50:60:   required from here
/usr/include/c++/7/bits/hashtable_policy.h:87:34: error: no match for call to '(const std::hash<wcg::BlockCacheKey>) (const wcg::BlockCacheKey&)'
  noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
           ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/move.h:54:0,
                 from /usr/include/c++/7/bits/stl_pair.h:59,
                 from /usr/include/c++/7/bits/stl_algobase.h:64,
                 from /usr/include/c++/7/memory:62,
                 from main.cpp:3:
/usr/include/c++/7/type_traits: In instantiation of 'struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<wcg::BlockCacheKey> >, std::__detail::__is_noexcept_hash<wcg::BlockCacheKey, std::hash<wcg::BlockCacheKey> > > >':
/usr/include/c++/7/bits/unordered_map.h:103:66:   required from 'class std::unordered_map<wcg::BlockCacheKey, std::shared_ptr<wcg::Block> >'
block_cache.h:50:60:   required from here
/usr/include/c++/7/type_traits:154:31: error: 'value' is not a member of 'std::__and_<std::__is_fast_hash<std::hash<wcg::BlockCacheKey> >, std::__detail::__is_noexcept_hash<wcg::BlockCacheKey, std::hash<wcg::BlockCacheKey> > >'
     : public __bool_constant<!bool(_Pp::value)>
                               ^~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/unordered_map:48:0,
                 from block_cache.h:13,
                 from main.cpp:5:
/usr/include/c++/7/bits/unordered_map.h: In instantiation of 'class std::unordered_map<wcg::BlockCacheKey, std::shared_ptr<wcg::Block> >':
block_cache.h:50:60:   required from here
/usr/include/c++/7/bits/unordered_map.h:103:66: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<wcg::BlockCacheKey> >, std::__detail::__is_noexcept_hash<wcg::BlockCacheKey, std::hash<wcg::BlockCacheKey> > > >'
       typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc>  _Hashtable;
                                                                  ^~~~~~~~~~
/usr/include/c++/7/bits/unordered_map.h:110:45: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<std::hash<wcg::BlockCacheKey> >, std::__detail::__is_noexcept_hash<wcg::BlockCacheKey, std::hash<wcg::BlockCacheKey> > > >'
       typedef typename _Hashtable::key_type key_type;

最佳答案

让我们看看BlockCache.h .你向编译器保证 BlockBlockCacheKey存在并最终将被定义——在这一点上它们是不完整的类型。只要您不以要求它们完整的方式使用它们,就可以正常工作:形成引用、指针甚至 std::shared_ptr s 到不完整的类型是可以的。参见 here获取您不能用它们做的事情的列表。

您使用 BlockCacheKey 违反了此规定(和 Block )在 std::unordered_map<BlockCacheKey, std::shared_ptr<Block>> 中- 实例化 std::unordered_map<Key, Value>模板(声明该类型的成员所必需的),KeyValue类型必须完整。

想象一下 sizeof(std::unordered_map<Key, Value>)取决于 sizeof(Key) (这将在其权利范围内)。只有前向声明 Key , sizeof(Key)将是未知的,因此 sizeof(std::unordered_map<Key, Value>)将是未知的,因此你的 BlockCache 的大小将是未知的(即使在您定义它之后!)。编译器无法处理它,这就是为什么不允许您这样做的原因。

Last thing to note, I do not want to include block_cache_key.h and block.h in block_cache.h

这是不可能的(正如您所观察到的那样,不需要用户发出时髦的包含命令)。实例化 std::map<BlockCacheKey, Whatever> , BlockCacheKey 的定义必须知道,你只能从包含它的标题中得到。我相信 Block 也是如此在std::shared_ptr<Block>您打算用作 map 值类型的类型。

关于c++ - 为什么我需要在以下示例中的 block_cache.h 之前包含 block_cache_key.h 和 block.h?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52168175/

相关文章:

c++ - 在映射中搜索元组的一部分作为键

c++ - 无序 map 占用大量空间

C++ 无序_Map : Receiving "error: expected unqualified-id before ‘[’ token"at Compile

c++通过枚举定义对象类型

c++ - 确定给定一组数字中的任何一个数字是否为零的最有效方法是什么?

c++ - 将函数作为参数传递给.cpp 文件中的函数模板时如何声明?

c++ - 基于字符串的数组,char列表转换

c++ - 即时翻译 Qt QML 应用程序

c++ - 使用 std::unordered_map 的模板实例化警告

c++ - 遍历 unordered_map cpp 的 unordered_map 中的元素