8

クラステンプレートがありFoo<T>ます。

Bar2つのsを取りFoo、を返す非メンバー関数を実装したいと思いますFoo。発信者が書くよりもBar自然になるので、私は非会員になりたいです。計算が簡単で頻繁なので、私もなりたいです。Bar(f1, f2)f1.Bar(f2)Barinline

template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
  ...
}

秘訣は、のプライベートデータBarにアクセスする必要があることです。Fooプライベートデータへのアクセサーを持たない方がいいです。プライベートデータをユーザーに公開する正当な理由はありません。Barだから私はの友達を作りたいですFoo

template <typename T>
class Foo {
  ...
  private:
    T w, x, y, z;
    friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};

ここで私は問題にぶつかります。コンパイラは文句を言います:

フレンド宣言が関数テンプレートの特殊化を参照している場合、インライン指定子は使用できません。

このルールは標準によって課されていますか、それともMSVC ++に固有ですか?

これが私が試したことです:

  • const Barpublic member関数を作成してから、単に。を返す​​非メンバーバージョンを宣言しますlhs.Bar(rhs)。これは最もハッキーな解決策のようです。

  • inlineコンパイラがヒントに関係なくインライン化を決定することを知って、ヒントを削除します。次に、これは単一定義規則に違反しますか?関数テンプレートであるため、ヘッダーファイルで定義する必要があります。

  • ダミーのテンプレートタイプを使用してメンバー関数を宣言します。

    template <typename T>
    class Foo {
      ...
      private:
        T w, x, y, z;
    
        // Note that this declaration doesn't actually use Dummy.  It's just there to
        // satisfy the compiler.     
        template <typename Dummy>
        friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
    };
    

なぜそれが機能するのか完全にはわかりませんが、コンパイラーは満足しています。

より良い解決策はありますか?

4

3 に答える 3

5

計算が簡単な場合は、次のように記述します。

template <typename T>
class Foo {
  ...
  private:
    T w, x, y, z;
  public:
    friend Foo Bar(const Foo &lhs, const Foo &rhs) {
        ...
    }
};

これはODRに反するものではありません。これは、外部リンケージを備えたインライン関数です(3.2 / 5は、定義が同一であることを条件として、これをODRから除外します。7.1.2/ 3はインラインであると言います)。

ただし、これは関数テンプレートBar<T>を定義するのではなく、の関数オーバーロードのセットを定義するだけですBar。質問に記載されていない理由があるかもしれません。それは、実際にテンプレートが必要なため、これが機能しないことを意味します。

于 2011-03-14T19:46:15.753 に答える
2

私はオプション1が一番好きです:

template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
    return lhs.Bar(rhs);
}

template <typename T>
class Foo {
  ...
    Foo<T> Bar(const Foo<T> &other) const;
  private:
    T w, x, y, z;
};

次に、機能はクラス内に安全に含まれますが、便宜上ラッパー関数を提供します。

于 2011-03-14T19:46:43.913 に答える
1

バーはテンプレートであるため、フレンド宣言でもテンプレートである必要があります。

必ずしもダミーパラメータを使用する必要はありませんが、使用することもできます

 template <typename U>
 friend Foo<U> Bar(const Foo<U> &lhs, const Foo<U> &rhs);

スコープにはすでに外部Tが存在するため、ここではテンプレートパラメータとしてTを使用できません。

于 2011-03-14T19:48:27.180 に答える