3

我将详细概述我的问题以解释我想要实现的目标,如果您想忽略我的问题的细节,问题在最后一段。

我有一个类设计问题,我希望将任何类型的值传递给函数push()pop()这些函数会将传递的值转换为字符串表示形式,该字符串表示形式将附加到类内部的字符串中,从而有效地创建数据流。反过来会发生pop(),获取流并将流前面的几个字节转换回指定的类型。

制作push()pop()模板绑定stringstream是一个明显的解决方案。但是,我希望在 DLL 中使用此功能,我可以在其中更改字符串的存储方式(例如加密或压缩),而无需重新编译客户端。T如果算法发生变化,则需要重新编译类型模板。

我的下一个想法是只使用 , , 等函数pushByte()pushInt()popByte()popInt()允许我在不重新编译客户端的情况下更改实现,因为它们仅依赖于静态接口。这样就好了。但是,它不是那么灵活。例如,如果一个值从一个字节更改为一个短字节,则与该值对应的所有 pushByte() 实例都需要更改为pushShort()popByte()类似于popShort()。重载pop()push()解决这个问题会导致类型冲突(导致显式转换,这最终会导致同样的问题)。

有了上面的想法,我就可以创建一个工人阶级了。但是,我想知道如何编译专门的模板。如果我创建push<byte>()and push<short>(),这将是一个特定类型的重载,并且从 byte 到 short 的更改会自动切换使用的模板,这将是理想的。

现在,我的问题是,如果我只使用专门的模板来模拟这种重载(没有 type 的模板T),所有的专门化是否都会编译到我的 DLL 中,从而允许我在不重新编译客户端的情况下调度新的实现?T还是在客户端编译时以与模板类型相同的方式选择或删除专用模板?

4

2 回答 2

2

首先,您不能拥有专门的模板而没有专门的基本模板。只是不允许。你必须从一个模板开始,然后你可以提供它的专业化。

您可以通过任意一组类型显式实例化模板,并将所有这些实例化编译到您的 DLL 中,但我不确定这是否真的能为您完成很多。归根结底,模板基本上是一种编译时形式的多态性,您似乎需要(至少是有限形式的)运行时多态性。

我可能只是使用重载。我猜你正在谈论的问题出现在以下顺序上:

int a;
byte b;

a = pop();
b = pop();

您基本上只是pop在返回类型上重载(众所周知,这是不允许的)。我会很简单地避免这种情况——而不是返回值,而是传递对要修改的值的引用:

int a;
byte b;

pop(a);
pop(b);

这不仅可以让重载解析起作用,而且至少对我来说看起来也更干净(尽管可能我刚刚写了太多汇编语言,所以我习惯了“流行斧”之类的东西)。

于 2010-07-20T16:40:55.253 回答
1

听起来您有两个相反的因素:

  1. 您希望您的客户能够推送/弹出/等。每个数字类型。模板似乎是一种自然的解决方案,但这与一致的(只需要编译一次)实现不一致。
  2. 当您更改实现方面时,您不希望您的客户必须重新编译。pimpl习惯用法似乎是一个自然的解决方案,但这与通用(适用于任何类型)实现不一致。

根据您的描述,听起来您只关心数字类型,而不是任意 T。您可以在头文件中为每个模板显式声明特化,并在源文件中定义它们,客户端将使用您定义的特化而不是编译自己的特化。特化是编译时多态性的一种形式。现在您可以将它与运行时多态性结合起来——根据与类型无关的实现类来实现特化。您的实现类可以使用boost::variant来执行此操作,因为您提前知道可能的 T 的范围(boost::variant<int, short, long, ...>)。如果 boost 不适合你,你可以自己想出一个类似的方案,只要你关心的 T 数量是有限的。

于 2010-07-20T16:57:50.457 回答