10

类 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 );
}

开始编辑

对阿尔夫:

我无法使用

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 ....; }

?

结束编辑

开始编辑2

致艾米林德:

这很有趣,但出于同样的原因,我无法使用来自 Widget 的派生(或者可能更清晰的将公共部分重构为父类 GeneralWidget 的解决方案)。共同的部分并不完全共同。它们的声明和定义看起来相同,但因为它们使用了特征,所以它们最终完全不同。

结束编辑2

4

4 回答 4

7
#include <assert.h>

template<typename Type> struct Widget
{
    Widget() {}
    char common_fn() { return 'a'; }
    int uncommon_fn() { return 1; }
};

template<>
int Widget<char>::uncommon_fn() { return 2; }

int main()
{
    Widget<char> WidgetChar;
    assert( WidgetChar.common_fn() == 'a' ); // OK
    assert( WidgetChar.uncommon_fn() == 2 );
}
于 2011-08-19T03:38:31.303 回答
1

首先,这在 C++ 中并不是真正受支持的事情。不幸的是,模板专业化要求您重新定义所有方法。

您可以将常用方法放在基类中,然后通过继承包含它们,尽管我自己的经验是混合包(父类中的函数与在所有情况下都是子类;友谊的工作方式很奇怪,如果基类也是一个模板,你必须在你想使用它的任何成员时完全指定它[除了在 MS 编译器上]。操作符也不能很好地工作) . 您可以通过复制粘贴常用方法来做到这一点,这正是您要避免的。或者,作为复制粘贴的折衷方案,您可以让编译器为您进行复制粘贴:

template<> struct Widget<char>
{
    #include "Widget_common.hpart"
    int uncommon_fn() { return 2; }
};

然后你制作一个名为“Widget_common.hpart”的文件,其中包含

// This file contains common functions for the Widget<> template, and will be #included
// directly into that template; it should not be included as a standalone header.
char common_fn() { return 'a'; }

我想你也可以只使用标准的 .h 扩展名。这绝对是对预处理器的滥用,但它可以满足您的要求,避免了模板继承的麻烦(而且它们确实很痛苦),并且只允许您保留公共代码的一个副本。如果有人想批评这是多么可怕的组合,请使用改进的解决方案;)。

于 2011-08-19T04:37:32.620 回答
0

理想情况下,在class专门化的情况下,我们应该专门化所有需要的方法。如果您不希望这样,那么以下技巧有效(有某些限制):

template<>
struct Widget<char> : Widget<int>
{
  //...
};

为了简单起见,我<int>认为它不是专门的(你可以把一些东西 Widget<void**>放在更安全的一边)。

assert( WidgetChar.common_fn() == 'a' ); // ok
于 2011-08-19T03:34:44.740 回答
0

我确实看过你关于特质的另一篇文章,但看到你似乎通过决定不使用专业化解决了你的问题。但是,为了其他遇到同样问题的人的利益,我有另一个人们可能想要考虑的解决方案。

无需尝试提取不常见的功能,您可以将常见的功能提取到它自己的类中,然后在类特化中提供包装函数。任何默认构造函数或析构函数甚至都不需要包装!

#include <cassert>

template<typename Type> struct WidgetCommon
{
    char common_fn() { return 'a'; } // 1,000,000 line function here :D
};

template<typename Type> struct Widget
{
    Widget() {}
    char common_fn() { return common.common_fn(); }
    int uncommon_fn() { return 1; }

private:
    WidgetCommon<Type> common;
};

template<> struct Widget<char>
{
    Widget() {}
    char common_fn() { return common.common_fn(); }
    int uncommon_fn() { return 2; }

private:
    WidgetCommon<char> common;
};

int main()
{
    Widget<char> WidgetChar;
    assert( WidgetChar.common_fn() == 'a' );
    assert( WidgetChar.uncommon_fn() == 2 );

    Widget<int> WidgetInt;
    assert( WidgetInt.common_fn() == 'a' );
    assert( WidgetInt.uncommon_fn() == 1 );
}

在这种情况下,它确实增加了代码量,但常见的实现只存在一次。创建更多的专业化只需要复制包装样板而不是行为代码。在可能有数百行通用代码的现实世界中,这种方法可以避免大量重复。

于 2013-01-11T00:31:26.547 回答