8

現在、「Effective C++」を読んでいますが、これに似たコードを含む章があります。

template <typename T>
class Num {
public:
  Num(int n) { ... }
};

template <typename T>
Num<T> operator*(const Num<T>& lhs, const Num<T>& rhs) { ... }

Num<int> n = 5 * Num<int>(10);

この本は、コンパイラが暗黙的な型キャストを使用してテンプレートを特殊化することを期待できないため、これは機能しない (そして実際に機能しない) と述べています。

解決策として、「friend」構文を使用してクラス内で関数を定義することをお勧めします。

//It works
template <typename T>
class Num {
public:
  Num(int n) { ... }

  friend 
  Num operator*(const Num& lhs, const Num& rhs) { ... }
};

Num<int> n = 5 * Num<int>(10);

そして、この本は、テンプレート クラス型への暗黙的な変換が必要なときはいつでも、このフレンド宣言を使用することを提案しています。そして、それはすべて理にかなっているようです。

しかし、演算子ではなく、共通の関数で同じ例を使用できないのはなぜでしょうか?

template <typename T>
class Num {
public:
  Num(int n) { ... }

  friend 
  void doFoo(const Num& lhs) { ... }
};

doFoo(5);

今回は、コンパイラは「doFoo」がまったく見つからないという不平を言っています。そして、クラス外で doFoo を宣言すると、合理的なタイプの不一致エラーが発生します。「友達…」の部分が無視されているようです。

私の理解に問題はありますか?この場合、関数と演算子の違いは何ですか?

4

3 に答える 3

3

理由はここにあります

doFoo(5);

パラメータfooを指定すると、コンパイラにはを見つける方法がありません。intこれは、次のように友達のオペレーターを呼び出すのと同じです。

Num<int> n = 5 * 10;

これは「機能」friend operator*しますが、クラスで定義されたものを呼び出すのNumではなく、組み込みの整数を呼び出してから、の変換コンストラクターoperator*からの暗黙的な変換を使用します。Num

于 2012-11-19T10:35:17.867 に答える
1

コアの問題はルックアップです。friend宣言は、名前空間レベルの関数の宣言を提供しますが、宣言は、それと親しくなっているクラス内でのみ使用できます。本が提供する例では、これは問題ではありません。関数は、囲んでいる型の 2 つの引数を取り、そのうちの 1 つが囲んでいる型である限り、Argument Dependent Lookup はクラスの定義内を調べて演算子を見つけます。あなたのケースではそうではありません.1つの引数があり、変換が必要なため、コンパイラはクラスの定義内を調べません。

これはテンプレートと変換に関係ないことに注意してください。

class A {
   friend void f( int ) {}
   friend void g( int, A ) {}
};
int main() {
   f(5);           // Error: lookup cannot find 'f' declared *only* inside A
   g(5,A());       // Ok, one argument is 'A', lookup will find the function
}

テンプレートが含まれていない上記のケースでは、名前空間レベルで宣言を追加して修正できる可能性がありますが、それは実際にはテンプレート クラスのオプションではありません。

class A {
   friend void f() { std::cout << "inside A\n"; }
};
void f(int);     // only declaration
int main() {
   f(5);         // "inside A"
}

フレンド宣言はテンプレート化されていない関数の宣言であるため、これはテンプレート (およびすべてのインスタンス化型) に対しては実行できません。テストのためだけにコードをいじることもできますが、

template <typename T>
struct Num {
   Num(int x) ...
   friend void f( Num const & );
};
Num<int> f(Num<int> const &);    // only declaration
int main() {
   f(5);
}
于 2012-11-19T12:51:19.257 に答える
0

はい、これらのコード コンパイラは、それを使用する方法を知りません。doFoo(5) のように

コンパイラは5がintであることを知りません

于 2012-11-19T10:55:34.153 に答える