【问题标题】:Class member variable that takes the class as a template以类为模板的类成员变量
【发布时间】:2013-07-04 23:41:44
【问题描述】:

因此,在最近的一个 C++ 项目中,我实现了一个类似数据包工厂的系统,其中每个新的数据包类都使用静态寄存器自动注册自己。其中一种数据包类型如下:

class Packet0Connect : public Packet{
public:
    Packet0Connect();
    Packet0Connect(const std::string& name, const std::string& info);
    virtual void write(std::ostream& os) const;
    virtual void read(std::istream& is);
    virtual Packet* clone() const;
    std::string name, info;
private:
    static const PacketRegister<Packet0Connect> registry;
};

这是 PacketRegister 的样子:

template<class P>
class PacketRegister{
public:
    PacketRegister(){
        PacketMap* packetMap = PacketManager::getPacketMap();
        if(packetMap->count(prototype.packetID) == 0){
            packetMap->insert(std::make_pair(prototype.packetID, (const Packet*)&prototype));
        }
    }
    P prototype;
};

注册表变量在实现文件的顶部正确初始化,并在其构造函数中添加到特定数据包类型(在本例中为 Packet0Connect)及其 ID 的映射。我非常喜欢我设法做到这一点的方式,因为它不会在堆栈上分配任何内存。以上在 Mac OSX 上使用 GCC 4.2.1 编译良好,但是,当我尝试在 32 位 Windows Vista 上使用 Visual C++ 2010 编译时,我遇到了这个错误:

error C2079: 'PacketRegister<P>::prototype' uses undefined class 'Packet0Connect'
    with
    [
        P=Packet0Connect
    ]
    see reference to class template initialization 'PacketRegister<P>' being compiled
    with
    [
        P=Packet0Connect
    ]

在对错误进行了一些谷歌搜索后,我发现当您尝试使用前向声明的类作为模板参数时,它通常会被抛出。这确实是有道理的,因为当 PacketRegister 存在时,Packet0Connect 并没有完全定义,但必须有一种方法可以使其与 VC++ 一起使用。我知道我可以在定义类之后将寄存器设为全局变量,但如果我可以让它作为静态成员变量工作,我不希望这样做。

【问题讨论】:

  • 您可以将P prototype 设为PacketRegister::PacketRegister() 的局部变量。不确定仅此一项是否有帮助,但如果没有,您可以将PacketRegister::PacketRegister() 的定义移出界限,仅在Packet0Connect 声明之后包含它
  • 这可能行得通,但是当构造函数返回时,该变量将超出范围,从而使映射指针无效。
  • 啊,是的,我的浏览器窗口不够宽,无法看到您正在使用该地址。顺便说一句,你有什么理由不能使用标准 C++ RTTI 机制来代替prototype
  • 在这种情况下,您建议我如何使用 RTTI?

标签: c++ templates


【解决方案1】:

这是因为编译器无法确定Packet0Connect 的大小。将Packet0Connect::registry 的类型从PacketRegister&lt;Packet0Connect&gt; 更改为PacketRegister&lt;Packet0Connect&gt; *

【讨论】:

  • 然后我将不得不用new 初始化指针,而且我宁愿把东西放在堆栈之外,而不是因为它与静态变量有很大的不同。
  • @Jsnman 请注意,Packet0Connect 包含一个 PacketRegister,而一个 PacketRegister 包含一个 Packet0Connect。你真的想要堆栈中的无限递归吗?
  • 我想我会避免这种情况,因为 PacketRegister 是静态的。那不是说没有递归吗?
【解决方案2】:

也许 PacketRegister 和 Packet0Connect 都相互依赖,而您没有在 PacketRegister 之前声明 Packet0Connect。只有给定的代码没有问题。检查依赖关系,你可能会前向声明它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-25
    • 2012-05-25
    • 2023-03-31
    • 1970-01-01
    • 2017-02-19
    • 2017-05-10
    相关资源
    最近更新 更多