C++模板专业化编译

发布于 2024-09-10 19:13:24 字数 1139 浏览 8 评论 0原文

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

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

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

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

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

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

I'm going to outline my problem in detail to explain what I'm trying to achieve, the question is in the last paragraph if you wish to ignore the details of my problem.

I have a problem with a class design in which I wish to pass a value of any type into push() and pop() functions which will convert the value passed into a string representation that will be appended to a string inside the class, effectively creating a stream of data. The reverse will occur for pop(), taking the stream and converting several bytes at the front of the stream back into a specified type.

Making push() and pop() templates tied with stringstream is an obvious solution. However, I wish to use this functionality inside a DLL in which I can change the way the string is stored (encryption or compression, for example) without recompilation of clients. A template of type T would need to be recompiled if the algorithm changes.

My next idea was to just use functions such as pushByte(), pushInt(), popByte(), popInt() etc. This would allow me to change the implementation without recompilation of clients, since they rely only on a static interface. This would be fine. However, it isn't so flexible. If a value was changed from a byte to a short, for example, all instances of pushByte() corresponding to that value would need to be changed to pushShort(), similarly for popByte() to popShort(). Overloading pop() and push() to combat this would cause conflictions in types (causing explicit casting, which would end up causing the same problem anyway).

With the above ideas, I could create a working class. However, I wondered how specialized templates are compiled. If I created push<byte>() and push<short>(), it would be a type specific overload, and the change from byte to short would automatically switch the template used, which would be ideal.

Now, my question is, if I used specialized templates only to simulate this kind of overloading (without a template of type T), would all specializations compile into my DLL allowing me to dispatch a new implementation without client recompilation? Or are specialized templates selected or dropped in the same way as a template of type T at client compilation time?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

街道布景 2024-09-17 19:13:24

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

您可以在任意类型集上显式实例化模板,并将所有这些实例化编译到您的 DLL 中,但我不确定这是否真的能为您带来多大帮助。最终,模板基本上是多态性的编译时形式,并且您似乎需要(至少是有限形式的)运行时多态性。

我可能只会使用重载。我猜你正在谈论的问题是由以下顺序引起的:

int a;
byte b;

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

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

int a;
byte b;

pop(a);
pop(b);

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

First of all, you can't just have specialized templates without a base template to specialize. It's just not allowed. You have to start with a template, then you can provide specializations of it.

You can explicitly instantiate a template over an arbitrary set of types, and have all those instantiations compiled into your DLL, but I'm not sure this will really accomplish much for you. Ultimately, templates are basically a compile-time form of polymorphism, and you seem to need (at least a limited form of) run-time polymorphism.

I'd probably just use overloading. The problem that I'd guess you're talking about arises with something on the order of:

int a;
byte b;

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

Where you'd basically just be overloading pop on the return type (which, as we all know, isn't allowed). I'd avoid that pretty simply -- instead of returning the value, pass a reference to the value to be modified:

int a;
byte b;

pop(a);
pop(b);

This not only lets overload resolution work, but at least to me looks cleaner as well (though maybe I've just written too much assembly language, so I'm accustomed to things like "pop ax").

街角迷惘 2024-09-17 19:13:24

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

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

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

It sounds like you have 2 opposing factors:

  1. You want your clients to be able to push/pop/etc. every numeric type. Templates seem like a natural solution, but this is at odds with a consistent (only needs to be compiled once) implementation.
  2. You don't want your clients to have to recompile when you change implementation aspects. The pimpl idiom seems like a natural solution, but this is at odds with a generic (works with any type) implementation.

From your description, it sounds like you only care about numeric types, not arbitrary T's. You can declare specializations of your template for each of them explicitly in a header file, and define them in a source file, and clients will use the specializations you've defined rather than compiling their own. The specializations are a form of compile time polymorphism. Now you can combine it with runtime polymorphism -- implement the specializations in terms of an implementation class that is type agnostic. Your implementation class could use boost::variant to do this since you know the range of possible T's ahead of time (boost::variant<int, short, long, ...>). If boost isn't an option for you, you can come up with a similar scheme yourself so long as you have a finite number of Ts you care about.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文