Области с использованием-директивы в объявлении 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*/);
};
Это имеет три отличительных преимущества.
- Содержимое целых пространств имен не вводится. Это помогает легче избежать конфликтов имен.
- У вас есть список перед объявлением класса того, что ваш класс зависит от правильной работы.
- Ваши объявления функций чисты.
Пожалуйста, поправьте меня, если я ошибаюсь; Я только кратко проверил это. Быстро написал пример, и он скомпилирован.