10

クラスWidgetには、すべてのパラメータータイプに適用されるいくつかの関数(共通関数)と、特定のタイプに特化する必要があるその他の関数(一般的でない関数)があります。

g ++は、ウィジェットの特殊化はuncommon_fn()だけでなくcommon_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 ....; }

終了編集

begin-edit2

iammilindへ:

これは興味深いことですが、同じ理由でWidgetからの派生(または共通部分を親クラスGeneralWidgetにリファクタリングするより明確なソリューション)を使用することはできません。共通部分は完全に共通ではありません。それらの宣言と定義は同じように見えますが、特性を使用しているため、最終的にはまったく異なります。

end-edit2

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拡張子を使用することもできます。これは間違いなくプリプロセッサの悪用ですが、要求どおりに機能し、テンプレート継承の問題を回避し(実際には非常に苦痛です)、共通コードのコピーを1つだけ保持できます。そして、これが恐ろしい恨みであると誰かが批判したい場合は、改善された解決策でそうしてください;)。

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

この場合、コードの量は増えますが、一般的な実装は1回だけ存在します。より多くのスペシャライゼーションを作成するには、動作コードではなく、ラッパーのボイラープレートを複製するだけで済みます。数百行の一般的なコードが存在する可能性がある現実の世界では、このアプローチにより多くの重複を回避できます。

于 2013-01-11T00:31:26.547 に答える