避免模板专业化中函数定义的重复
Widget 类具有一些适用于所有参数类型的函数(常见函数)和其他需要针对给定类型进行专门化的函数(不常见函数)。
g++ 坚持认为 Widget 的特化还应该定义 common_fn() 而不仅仅是 uncommon_fn(),但这从一开始就违背了使用特化的目的。如何避免重复 common_fn()?
#include <cassert>
template<typename Type> struct Widget
{
Widget() {}
char common_fn() { return 'a'; }
int uncommon_fn() { return 1; }
};
template<> struct Widget<char>
{
Widget() {}
int uncommon_fn() { return 2; }
};
int main()
{
Widget<char> WidgetChar;
assert( WidgetChar.common_fn() == 'a' ); // Error
assert( WidgetChar.uncommon_fn() == 2 );
}
begin-edit
to Alf:
我无法使用
template<> int Widget<char>::uncommon_fn() { return 2; }
,因为一些不常见的函数需要返回特征类型(因此通过使实际类型原始来简化是过度的)。
或者实际上有一种方法可以让编译器在编写时识别 typename Foo::Bar
struct Foo { typedef FooBar Bar; };
template<> typename Foo::Bar Widget<Foo>::uncommon_fn() { return ....; }
?
end-edit
begin-edit2
到iammilind:
这很有趣,但我无法使用 Widget 的派生(或者将公共部分重构为父类的可能更清晰的解决方案) GeneralWidget)出于同样的原因。共同的部分并不完全共同。它们的声明和定义看起来相同,但因为它们使用特征,所以它们最终完全不同。
结束编辑2
The class Widget has some functions that apply for all parameter types (common functions) and other functions that need to be specialized for given types (the uncommon functions).
g++ insists that the specialization for Widget should also define common_fn() and not just uncommon_fn(), but that defeats the purpose of using specialization in the first place. How can one avoid repeating common_fn()?
#include <cassert>
template<typename Type> struct Widget
{
Widget() {}
char common_fn() { return 'a'; }
int uncommon_fn() { return 1; }
};
template<> struct Widget<char>
{
Widget() {}
int uncommon_fn() { return 2; }
};
int main()
{
Widget<char> WidgetChar;
assert( WidgetChar.common_fn() == 'a' ); // Error
assert( WidgetChar.uncommon_fn() == 2 );
}
begin-edit
to Alf:
I am unable to use
template<> int Widget<char>::uncommon_fn() { return 2; }
because some of the uncommon functions need to return a trait type (and so it was excessive to simplify by making the actual type primitive).
Or is there in fact a way to make the compiler recognize typename Foo::Bar
when writing
struct Foo { typedef FooBar Bar; };
template<> typename Foo::Bar Widget<Foo>::uncommon_fn() { return ....; }
?
end-edit
begin-edit2
to iammilind:
That's interesting, but I am unable to use derivation from Widget (or the possibly clearer solution of refactoring the common parts into a parent class GeneralWidget) for the same reason. The common parts are not entirely common. Their declarations and their definitions look the same, but because they use traits they are at the end quite different.
end-edit2
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先,这在 C++ 中并不是真正受支持的事情。不幸的是,模板专业化要求您重新定义所有方法。
您可以将常用方法放在基类中,然后通过继承来包含它们,尽管我自己的经验是一个混合包(父类中的函数与父类中的函数的行为方式并不完全相同)在所有情况下都是子类;友谊的工作方式很奇怪,如果基类也是一个模板,那么每当您希望使用它的任何成员时都必须完全指定它(除了在 MS 编译器上)。 。您可以通过复制粘贴常用方法来完成此操作,这正是您想要避免的。或者,作为复制粘贴的折衷方案,您可以让编译器为您进行复制粘贴:
然后您创建一个名为“Widget_common.hpart”的文件,其中包含
您也可以只使用标准 .h 扩展名,我想。这绝对是预处理器滥用,但它满足了您的要求,避免了模板继承的麻烦(它们确实非常痛苦),并且让您只保留通用代码的单个副本。如果有人想批评这是多么可怕的组装,请使用改进的解决方案来批评;)。
First off, this isn't really a supported thing to do in C++. Template specialization requires you to redefine all the methods, unfortunately.
You can put your common methods in a base class, and then include them by inheritance, although my own experience with that has been a mixed bag (a function in the parent class just doesn't behave quite the same way as a function in the child class in all cases; friendship works strangely, and if the base class is also a template, you have to fully specify it whenever you wish to use any of its members [except on MS compilers]. Operators never work quite as well either). You can do it by copy-pasting your common methods, which is precisely what you're trying to avoid. Or, as a compromise on copy-pasting, you can have the compiler do your copy-pasting for you:
Then you make a file called "Widget_common.hpart" that contains
You can also just use the standard .h extension, I suppose. This is definitely preprocessor abuse, but it does what you ask for, avoids the template inheritance headaches (and they really are quite painful), and lets you keep only a single copy of your common code. And if anyone wants to criticize what a horrible kludge this is, do so with an improved solution ;).
理想情况下,在
class
特化的情况下,我们应该特化所有必需的方法。如果您不希望这样,那么可以使用以下技巧(有一定的限制):为了简单起见,我放置了
,它被认为不是专门的(您可以放置类似的东西Widget
为了更安全)。Ideally, in the case of
class
specialization, we are suppose to specialize all the required methods. If you don't want that, then following trick works (with certain limitations):I am put
<int>
for simplicity which is assumed to be not specialized (you can put something likeWidget<void**>
to be on safer side).我确实看过您关于特质的其他帖子,但发现您似乎通过决定不使用专业化来解决了您的问题。但是,为了其他遇到同样问题的人的利益,我有另一个人们可能想要考虑的解决方案。
您可以将常见功能提取到自己的类中,而不是尝试提取不常见的功能,然后在类专业化中提供包装函数。任何默认的构造函数或析构函数甚至不需要包装!
这种情况下,确实增加了代码量,但是通用的实现只存在一次。创建更多的专业化只需要复制包装器样板而不是行为代码。在现实世界中,可能有数百行公共代码,这种方法可以避免大量重复。
I did take a look at your other post regarding traits, but saw that you seem to have solved your problem by deciding not to use specialization. But, for the benefit of others who have had the same problem, I have another solution that people might want to consider.
Instead of trying to extract the uncommon functionality, you can extract the common functionality into a class of its own, and then provide wrapper functions in the class specializations. Any default constructors or destructors don't even need to be wrapped!
In this case, it does increase the amount of code, but the common implementation only exists once. Creating more specializations will only require duplicating the wrapper boilerplate rather than the behavioural code. In the real world, where there may be hundreds of lines of common code, this approach can avoid a lot of duplication.