5

operator "" (...)をフレンド関数として定義することは可能かつ/または有用ですか?

class Puzzle {
  friend Puzzle operator "" _puzzle(const char*, size_t);
  ...
};
void solve(Puzzle);
int main() {
  solve("oxo,xox"_puzzle);
};

名前空間でのみ定義されるルールのため、特に「有用」について考えています。特に、でoperator ""始まる識別子_はグローバル名前空間で予約されているためです。これはfriendここでこの規則に違反していますか? ですから、このカプセル化が不十分であることに何のメリットもありませんよね?

4

3 に答える 3

2

標準は、ユーザー定義リテラルの宣言に関する制限に言及している唯一の場所で、これを直接扱っています。§13.5.8/2:

declarator-id がliteral-operator-id である宣言は、名前空間スコープの関数または関数テンプレート (フレンド関数 (11.3) の場合もあります)、関数テンプレートの明示的なインスタンス化または特殊化、またはusing 宣言 (7.3.3)。

フレンドが名前空間スコープでも宣言されている場合、クラスまたは名前空間スコープでの定義に区別はありません。名前空間スコープでの定義の要件はないことに注意してください。これは、現在の言い回しとしての質問が主張しています。

名前空間のスコープで宣言されていない場合、ADL で見つけることができないため、友人は通常の非修飾名ルックアップによってスコープ内でプライベートに使用される可能性があります。これは、外部インターフェースではないリテラル演算子を宣言する唯一の方法です。

フレンドがクラス テンプレート内で定義されている場合、テンプレートの 2 つのインスタンス化により、名前空間スコープで 2 つの同じ名前の関数が生成されます。これらはクラス スコープの外では見えませんが、衝突します。

于 2011-09-11T02:11:37.010 に答える
1

構文に役立つ場合は、次のように、クラスでフレンドのユーザー定義リテラル演算子を宣言します。演算子自体は名前空間にあります。

class Integer;
namespace literals {
  Integer operator "" _I (const char *);
}

// Infinite precision integer 
class Integer {
  public:

  // Basic constructor & destructor
   Integer ();
  ~Integer ();

... rest of the interface ...

  // Literal operator
  friend Integer literals::operator "" _I (const char *);

  private:

  struct Detail;
  std::unique_ptr<Detail> detail;

};

using namespace literals;ユーザーは、必要な場合にのみ、ステートメントを使用して演算子をプルします。(そして、実際には、これはすべて親の名前空間にありますが、あなたはその考えを理解します)。

于 2011-12-05T00:48:27.173 に答える
0

標準によれば、はい、友人の宣言は合法であるべきです。ちなみに、名前はグローバル名前空間でもアンダースコアで始まるため、ユーザー コードとしては問題ありません。

フレンド宣言により、オペレーターはクラス プライベート データにアクセスできます。

私はフレンド リテラル演算子の有用性に疑問を持ち始めています。ユーザー定義の演算子は少数の引数リストしか持てないため、クラスを引数に入れる方法はありません。そのため、引数に依存するルックアップで正しい関数を見つける方法があります。私は正しいですか?

于 2011-09-09T19:55:16.417 に答える