web-dev-qa-db-ja.com

スコープ付きのusing-struct / class宣言内のディレクティブ?

私のC++ヘッダーファイルは、すべての完全修飾型(4つのネストされた名前空間まで深くなる)では非常に読みにくい(そして入力するのが本当に面倒)ことがわかりました。これは質問です(すべての答えはそれを実装するための厄介な代替手段を提供しますが、それはではありません質問です):強い理由がありますかC++言語の構造体とクラスにスコープ付きusing-directiveを導入することに対して(関数にスコープ付きusing-declarationを使用することは許可されていますが)?

例えば.

class Foo : public Bar
{
    using namespace System;
    using namespace System::Network;
    using namespace System::Network::Win32::Sockets;
    using Bar::MemberFunc; // no conflict with this

    // e.g. of how messy my header files are without scoped using-directive
    void FooBar(System::Network::Win32::Sockets::Handle handle, System::Network::Win32::Sockets::Error& error /*, more fully-qualified param declarations... */);
};

namespaceはキーワードなので、Bar::MemberFuncなどのスコープ付き使用宣言と競合しないように十分に区別できると思います。

編集:質問を注意深く読んでください--->私はそれを太字にしました。注意:ここでは、例の読みやすさを向上させる方法について話し合っていますnot。スコープ付きusing-directiveをC++言語で(つまり、キーワード/構成などを追加することによって)実装する方法を提案するのは[〜#〜] not [〜#〜]答え(既存のC++言語標準を使用してこれを実装するためのエレガントな方法を見つけることができれば、もちろんそれは答えになります)!

26
Zach Saw

クラススコープでのusing宣言が継承されていない場合、これは機能する可能性があります。この名前は、そのクラス宣言内、またはネストされたクラスの宣言内でのみ有効です。しかし、それはクラスの概念をもっと大きくすべきアイデアでオーバーロードするようなものだと思います。

In JavaおよびPython個々のファイルは、特別な方法で処理されます。他の名前空間からファイルに名前を挿入するimport宣言を持つことができます。 。これらの名前は(Pythonの場合とは異なりますが、ここで説明するには複雑すぎます)、そのファイル内にのみ表示されます。

私にとって、この種の能力はクラス宣言に結び付けられているのではなく、代わりに独自のスコープを与えられていると主張しています。これにより、意味がある場合は、挿入された名前をいくつかのクラス宣言で使用したり、関数定義で使用したりすることができます。

これが私が好むアイデアです。宣言を使用してクラスレベルの利点を提供しながら、これらのことを可能にするからです。

using {
   // A 'using' block is a sort of way to fence names in.  The only names
   // that escape the confines of a using block are names that are not
   // aliases for other things, not even for things that don't have names
   // of their own.  These are things like the declarations for new
   // classes, enums, structs, global functions or global variables.
   // New, non-alias names will be treated as if they were declared in
   // the scope in which the 'using' block appeared.

   using namespace ::std;
   using ::mynamespace::mytype_t;
   namespace mn = ::mynamespace;
   using ::mynamespace::myfunc;

   class AClass {
     public:
      AClass(const string &st, mytype_t me) : st_(st), me_(me) {
         myfunc(&me_);
      }

     private:
      const string st_;
      mn::mytype_t me_;
   };
// The effects of all typedefs, using declarations, and namespace
// aliases that were introduced at the level of this block go away
// here.  typedefs and using declarations inside of nested classes
// or namespace declarations do not go away.
} // end using.

// Legal because AClass is treated as having been declared in this
// scope.
AClass a("Fred", ::mynamespace::mytype_t(5));

// Not legal, alias mn no longer exists.
AClass b("Fred", mn::mytype_t);

// Not legal, the unqualified name myfunc no longer exists.
AClass c("Fred", myfunc(::mynamespace::mytype_t(5));

これは、関数内のローカル変数のブロックを宣言することに似ています。ただし、この場合、名前検索ルールを変更するスコープが非常に限定されていることを宣言しています。

9
Omnifarious

時々私はこれを行ってほぼ同じ効果を達成します:

namespace detail {
    using namespace System;
    using namespace System::Network;
    using namespace System::Network::Win32::Sockets;

    class Foo : public Bar
    {
         void FooBar(Handle handle, Error& error);
    };
}
using detail::Foo;
11
Timo

クラス宣言内でtypedefを使用して、同じことを実現できます

class Foo : public Bar
{
      typedef System::Network::Win32::Sockets::Handle Handle;
      typedef System::Network::Win32::Sockets::Error Error;

      void FooBar(Handle handle, Error& error);
};
0
Declan

多分名前空間エイリアス?

namespace MyScope = System::Network::Win32::Sockets;
0
nemethpeter