Области с использованием-директивы в объявлении struct/class?

Я нахожу, что мои файлы заголовков С++ довольно трудно читать (и очень утомительно печатать) со всеми полностью квалифицированными типами (которые занимают до 4 вложенных пространств имен). Это вопрос (все ответы дают беспорядочные альтернативы его реализации, но это не вопрос): Есть ли веская причина не вводить облачную директиву-директиву в структурах и классах на языке С++ (while разрешено ли использовать функции-декларации в функциях)?

например.

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.

EDIT: внимательно прочитайте вопрос --- > Я выделил его. Напоминание: мы не обсуждаем, как улучшить читаемость примера здесь. Представление о том, как можно реализовать реализованную директиву с использованием (например, путем добавления ключевых слов/конструкций и т.д.) На языке С++, НЕ является ответом (если бы вы могли найти элегантный способ реализовать это, используя существующие стандарты языка С++, то это конечно, ответ)!

Ответ 1

Учитывая, что объявления using в области класса не наследуются, это может сработать. Имя будет действительным только внутри этого объявления класса или внутри деклараций вложенных классов. Но я думаю, что это перегружает концепцию класса идеей, которая должна быть больше.

В 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));

Это аналогично объявлению блока для локальных переменных в функции. Но в этом случае вы объявляете очень ограниченную область действия, в которой вы будете изменять правила поиска имен.

Ответ 2

Иногда я делаю это для достижения почти того же эффекта:

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;

Ответ 3

Может быть псевдоним пространства имен?

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

Ответ 4

Вы можете использовать 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);
};

Ответ 5

Очевидным преимуществом пространств имен является то, что они позволяют избежать конфликтов имен. Однако, введя полное пространство имен в объявление класса, это преимущество аннулируется. Вполне возможно, что функция в пространстве имен System может противоречить вашей собственной функции Bar:: MemberFunc. Вы даже заметили это в своем примере кода, когда вы добавили комментарий "нет конфликта с этим".

Очевидно, вы не хотите вводить целые пространства имен в свой класс следующим образом:

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

И вы не можете добавлять более узкие области применения с помощью таких утверждений в объявление класса. Ввод их непосредственно в объявление класса является незаконным.

using System::Network::Win32::Sockets::Handle;
using System::Network::Win32::Sockets::Error;

Что вы можете сделать, это использовать неназванное пространство имен. Итак, ваш файл заголовка будет выглядеть примерно так:

namespace {
    using System::Network::Win32::Sockets::Handle;
    using System::Network::Win32::Sockets::Error;
}

class Foo : public Bar
{
    using Bar::MemberFunc;

    // clean!
    void FooBar(Handle handle, Error& error /*, more declarations*/);
};

Это имеет три отличительных преимущества.

  • Содержимое целых пространств имен не вводится. Это помогает легче избежать конфликтов имен.
  • У вас есть список перед объявлением класса того, что ваш класс зависит от правильной работы.
  • Ваши объявления функций чисты.

Пожалуйста, поправьте меня, если я ошибаюсь; Я только кратко проверил это. Быстро написал пример, и он скомпилирован.