web-dev-qa-db-ja.com

C ++ 11のすべて/ほとんどのセッター関数は、ユニバーサル参照を受け入れる関数テンプレートとして作成する必要がありますか?

Xメンバー変数を持つクラスNを考えてみましょう。それぞれ、いくつかのコピー可能movableタイプ、およびN対応するセッター関数。 C++ 98では、Xの定義は次のようになります。

class X
{
public:
    void set_a(A const& a) { _a = a; }
    void set_b(B const& b) { _b = b; }
    ...
private:
    A _a;
    B _b;
    ...
};

上記のクラスXのセッター関数は、左辺値と右辺値の両方の引数にバインドできます。実際の引数に応じて、このmightは一時的なものを作成し、will最終的にはコピーの割り当てになります。このため、コピー不可タイプはこのデザインではサポートされていません。

C++ 11では、移動セマンティクス、完全な転送、およびユニバーサル参照(Scott Meyersの用語)があり、次のように書き直すことで、セッター関数をより効率的かつ一般的に使用できます。

class X
{
public:
    template<typename T>
    void set_a(T&& a) { _a = std::forward<T>(a); }

    template<typename T>
    void set_b(T&& b) { _b = std::forward<T>(b); }
    ...
private:
    A _a;
    B _b;
    ...
};

ユニバーサル参照は、const/non -constvolatile/non -volatile、および一般的な任意の変換可能なタイプにバインドでき、一時的なものの作成を回避します値をoperator =に直接渡します。 Non-copiablemovableタイプがサポートされるようになりました。おそらく望ましくないバインディングは、static_assertまたはstd::enable_ifのいずれかを介して削除できます。

だから私の質問は:設計ガイドラインとして、C++ 11のすべての(たとえばほとんどの)セッター関数は、ユニバーサルを受け入れる関数テンプレートとして記述されるべきですか?参照?

より面倒な構文と、これらのセッター関数でコードを記述するときにIntellisenseのようなヘルパーツールを使用できないことは別として、「セッター関数を関数テンプレートとして受け入れる」という仮想原則に関連する欠点はありますか?可能な限りユニバーサル参照 "?

64
Andy Prowl

クラスAとBを知っているので、それらが移動可能かどうか、そしてこの設計が最終的に必要かどうかを知っています。 std::stringのようなものの場合、ここでパフォーマンスの問題があることがわかっていない限り、既存のコードを変更するのは時間の無駄です。 auto_ptrを扱っている場合は、それを取り除いてunique_ptrを使用します。

引数を取ることが通常は好まれます値でより具体的なことを何も知らない場合-など

void set_a(A a) { _a = std::move(a); }

これにより、移動性以外は何も必要とせずにAのコンストラクターを使用でき、比較的直感的なインターフェイスが提供されます。

37
Puppy