2

Source次のように、あるオブジェクト (または type ) の関連ビットを別の ( type の) にコピーするグローバル関数がありますTarget

template<typename Source , typename Target>
void partialCopy( Source& source , Target& target )
{
    // perform copy
}

グローバル関数で私が見つけた問題は、メンバー関数とは異なり、2 つの引数のどちらがソースでどちらがターゲットかをコーディングするときにすぐに明確にならないことです。したがって、次のようpartialCopy()すべてのクラスにメンバー関数が必要です。

struct Foo
{
    template<typename T>
    void partialCopy( T& target )
    {
        ::partialCopy( *this , target );
    }
};

現在の問題は、メンバー関数を多数のクラスにコピーする必要があることです。これは、コピー アンド ペースト プログラミングの許容できるケースですか? partialCopy次のように、ヘッダー ファイルpartialCopy.hを挿入し、プリプロセッサ インクルードを使用して各クラスに「挿入」することを検討しました。

struct Foo
{
    #include "partialCopy.h"
};


Foo f;
Bar b;
f.partialCopy( b );

これは機能しますが、どこでも実行されているのを見たことがなく、受け入れられないかどうかはわかりません。

partialCopyメンバー関数を共通の基本クラスに入れて継承しようとしましたが、thisキーワードが派生クラスではなく基本クラスを参照するため、これは機能しません。

さらに良い代替手段はありますか?お知らせ下さい。

編集

CRTP基本クラスの派生クラスに対して実行するというジョンの提案(削除されたスレッドで)はstatic_castうまく機能します。@ジョンはこれに回答を投稿してください。そのようにマークします。

4

5 に答える 5

5

私の意見では適切なので、これを回答として投稿しています。ただし、Henrik が最初にコメントしました。(しかし、これも私の最初の考えでした:))

定数参照

const&source パラメーターに (const-reference) を使用します。そうすれば、ターゲットと簡単に区別できます。

追加の利点は、部分コピー関数の const の正確性を検証して保証することです。

右辺値参照

のためにオーバーロードすることも考えられるかもしれませんSource&&。直接コピーされるバッファーがいくつかある場合、関数はそれを使用する可能性があります。

于 2013-02-12T12:17:16.037 に答える
3

このためにストリーム演算子をオーバーロードすることをお勧めします。

例えば

template<typename Source , typename Target>
void partialCopy(Source& source, Target& target)
{
    // perform copy
}

効果的に次のようになります。

template<typename Source , typename Target>
void operator>>(const Source& source, Target& target)
{
    // perform copy
}

(わかりやすくするために、Source パラメータが const& になったことにも注意してください。

だから、あなたは単に書くことができます

Foo f;
Bar b;
f >> b;

ソース オブジェクトとターゲット オブジェクトが何であるかがより明確になります。

于 2013-02-12T12:17:15.053 に答える
1

私はこの答えに少し遅れていますが、コピー&ペーストプログラミングのクリーンな代替手段としてCRTPを使用するソリューションに興味があるかもしれないと思いました。

ここでの問題は、メンバー関数を数十のクラスにコピーする必要があることです。これは、コピーアンドペーストプログラミングの許容できるケースですか?ヘッダーファイルpartialCopy.hにpartialCopyを配置し、プリプロセッサインクルードを使用して各クラスに「注入」することを検討しました[...]。

コードをコピーまたは#includeする代わりに、次のことを考慮してください。

// common code:
<template typename T>
class PartialCopyImplementer
{
public:
    template<typename D>
    void partialCopy(D& destination)
    {
        // ::partialCopy( *this , target );
    }
};

// concrete implementations
class Foo1 : public PartialCopyImplementer<Foo1> // CRTP implementation
{
// ...
};

// concrete implementations
class Foo2 : public PartialCopyImplementer<Foo2> // CRTP ensures Foo1 and Foo2
                                                 // do not have a common base
{
// ...
};
于 2013-02-15T11:48:42.893 に答える
0

どうですか:

template<class T>
struct from_impl
{
  T const& from;
  from_impl(T const& f) 
    : from(f)
  {}
};

template<class T>
from_impl<T> from(T const& f) {
  return from_impl(f);
}

template<class T>
struct to_impl
{
  T& to;
  to_impl(T& t) 
    : to(t)
  {}
};

template<class T>
to_impl<T> to(T& t) {
  return to_impl(t);
}
template<class T>
void to(T const&); // prevent using  with non-const values

template<class Source,class Target>
void partial_copy(from_impl<Source> source, to_impl<Target> target)
{
   // use source.from and target.to to perform copy
}

// usage:
T1 object1;
T2 object2;

partial_copy(from(object1),to(object2));

これにより、何をしたいのかが非常に明確になります。from_implとto_implは一種の参照のように機能し、fromとtoは簡単に使用できるようにファクトリ関数として機能します。次のような実装を試みることもできます。

partial_copy.from(Source).to(Target);
partial_copy(Source)->_(Target);

しかし、通常、これは多くの書き込みです。名前の衝突を防ぐためにpartial_copyを独自の名前空間に配置し、ユーザーがカスタマイズのために独自のオーバーロードを作成し、const&を使用してソースと宛先が何であるかを通知できるようにします。

于 2013-02-12T12:40:06.627 に答える
0

最もクリーンな方法は、おそらくpartialCopy無料の関数のままにして、そのように使用することです。本質的に問題はありません。たとえば、標準ライブラリ<algorithm>ヘッダー内のすべての関数は、オブジェクトで使用される自由な関数です。

foo.partialCopy(bar)また、どれがソースでどれが宛先かはあまり明確ではありません。からまたはpartialCopyコピーしますか? 一般に、このような場合はドキュメント/関数宣言を確認すると便利です。パラメータに明確な名前があり、適切なときにそれらを作成すると、オブジェクトがどのようにコピーされるかが明確になります。 barconst

于 2013-02-12T12:33:04.327 に答える