Ограниченная директива использования в объявлении структуры/класса?

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

e.g.

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.

РЕДАКТИРОВАТЬ: внимательно прочитайте вопрос --- > я выделил его жирным шрифтом. Напоминание: мы не обсуждаем здесь, как улучшить читабельность примера. Предложение о том, как может быть реализована директива использования с ограниченной областью действия (т. е. посредством добавления ключевых слов/конструкций и т. д.) в языке C++, является НЕ ответом (если бы вы могли найти элегантный способ реализовать это, используя существующий C++ норм языка, то это конечно был бы ответ)!


person Zach Saw    schedule 06.12.2010    source источник
comment
Лично я считаю, что это признак плохого дизайна, когда так много вложенных пространств имен.   -  person Omnifarious    schedule 06.12.2010
comment
Судя по вашим рассуждениям, .NET framework будет плохим дизайном.   -  person Zach Saw    schedule 06.12.2010
comment
@Zach Saw - это плохой дизайн C ++, не очень хороший дизайн Java и нормальный (но все же не фантастический) дизайн Python. И если это делает .NET framework для C++, то да, он не очень хорошо спроектирован. Однако я думаю, что С++ мог бы использовать предложенный вами механизм для ограничения области использования объявления. Это привело бы к тому, что сильно вложенные пространства имен были бы менее плохим дизайном в C++, чем в настоящее время.   -  person Omnifarious    schedule 06.12.2010
comment
@Omnifarious: вы можете сравнить STL с более обширными библиотеками, такими как библиотеки .NET и Java. Если бы стандартная библиотека C++ была более обширной, нам определенно пришлось бы разбить ее на большее количество пространств имен (и, конечно же, потратить 5 лет на поиск компромисса по поводу того, что это такое). Но нам определенно понадобится какая-то форма вложенных пространств имен. Лично я думаю, что это хорошая идея, но вы должны быть осторожны.   -  person Martin York    schedule 06.12.2010
comment
@Martin York - я не думаю, что вложенные пространства имен - это зло, которое никогда не следует посещать миру. Boost часто их использует. Я просто думаю, что их следует использовать экономно, и ваша глубина вложенности должна быть небольшой, а данное пространство имен должно иметь много имен. То, как в настоящее время работает С++, заставляет широко вложенные пространства имен вызывать проблемы, такие же, как у OP.   -  person Omnifarious    schedule 06.12.2010
comment
Ребят, вопрос, а есть веская причина не иметь этой фичи в языке?   -  person Zach Saw    schedule 06.12.2010
comment
@Omnifarious: Так в чем тогда причина /не/ вводить эту функцию в язык?   -  person Zach Saw    schedule 06.12.2010
comment
Предложение о том, как директива использования с областью действия может быть реализована на языке C++, НЕ является ответом! <- но это. Если я могу показать, что это можно реализовать на C++ сейчас, то это является очень веской причиной для того, чтобы не добавлять такую ​​функцию в язык явно.   -  person jalf    schedule 06.12.2010
comment
Возможно, это утверждение вводит в заблуждение. Но я имел в виду реализацию функции поверх существующего языка (т. е. путем введения новых конструкций/ключевых слов и т. д.). Если бы вы могли показать, что это можно реализовать на C++ сейчас (теперь это ключевое слово), то, конечно, это ответ.   -  person Zach Saw    schedule 06.12.2010


Ответы (5)


Учитывая, что объявления 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));

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

person Omnifarious    schedule 06.12.2010
comment
Опять же, вопрос в том, есть ли веская причина против введения директивы использования с ограниченной областью действия в структурах и классах языка C++? - person Zach Saw; 06.12.2010
comment
@Zach Saw - я исправил свой ответ, чтобы ответить на ваш вопрос. :-) - person Omnifarious; 06.12.2010
comment
Нет, это не будет похоже на мою идею. Производные классы не наследуют директиву использования — она ограничена только классом. Так что нет проблем с двусмысленностью в соответствии с вашим typedef. - person Zach Saw; 06.12.2010
comment
@Zach Saw - Хммм ... Хорошо, значит, этой проблемы не существует, потому что вы правы, другие виды использования объявлений не наследуются. Мне по-прежнему больше нравится моя идея с областью действия using, потому что я думаю, что она более гибкая и понятная. - person Omnifarious; 06.12.2010
comment
@Omnifarious: Опять же, это не отвечает на вопрос. Вы утверждаете, что у нас должна быть функция в языке — вопрос в том, почему мы должны не ее иметь. - person Zach Saw; 06.12.2010
comment
@Zach Saw - Мой аргумент в том, что другая связанная функция на самом деле была бы лучше и понятнее. - person Omnifarious; 06.12.2010
comment
@Omni: Это еще не функция. И мы не обсуждаем, как это должно выглядеть — мы обсуждаем, почему этого не должно быть. - person Zach Saw; 06.12.2010
comment
@Zach Saw - И я говорю, что мы не должны иметь его в той форме, о которой вы говорите, потому что таким образом он слишком ограничен по объему (каламбур). - person Omnifarious; 06.12.2010
comment
@Omni: Это просто пример - чтобы помочь понять, что я имел в виду под директивой использования с ограниченной областью действия в объявлении структуры/класса. Если вы не сможете найти переносимую функцию языка С++, которая более элегантно соответствует этим критериям, я не могу принять ваш ответ. - person Zach Saw; 06.12.2010
comment
@Omni: Лично я предпочитаю, чтобы он был ограничен по объему. Но это не то, о чем этот вопрос. Я полагаю, что это станет отличной темой для другого дня, если мы решим, что нет никаких причин, по которым C++ не должен поддерживать эту функцию с самого начала. - person Zach Saw; 06.12.2010
comment
@Zach Saw - Лично я думаю, что наличие идеи для более общей и / или более четкой функции - вполне веская причина для того, чтобы выступать против более ограниченной и менее ясной функции. - person Omnifarious; 06.12.2010
comment
@Omni: Это ваше представление об использовании директивы с ограниченным объемом по сравнению с моей. Опять же, это тема для другого дня, но прямо сейчас давайте установим, есть ли веская причина против внедрения этого в язык C++. - person Zach Saw; 06.12.2010
comment
Обычно комитет по стандартам работает наоборот. Есть ли веская причина для включения его в язык? C++ уже является огромным языком. Каждая новая функция действительно должна оправдывать стоимость, чтобы быть добавленной. Так является ли такая функция достаточно важной, чтобы оправдать увеличение размера языка? - person jalf; 06.12.2010
comment
В этом случае C++ обречен на вымирание, поскольку, исходя из этого рассуждения, они предпочли бы отдавать предпочтение устаревшим вещам, а не вводить новые функции, чтобы сделать язык более элегантным. - person Zach Saw; 06.12.2010
comment
Кстати, есть ли сильная причина для автоматического ключевого слова? - person Zach Saw; 06.12.2010
comment
@Zach Saw - это забавный пример. В C++0x ключевое слово auto было переназначено, и теперь есть веская причина для его использования. - person Omnifarious; 06.12.2010
comment
Что определяет, насколько сильна причина? Это объективно или субъективно? - person Zach Saw; 06.12.2010
comment
@ Зак Со - Консенсус. Это субъективно, но определяется мнением всей группы, а не одного человека. Я думаю, что можно привести веские доводы в пользу объявления с использованием области действия и, возможно, псевдонимов с областью действия. - person Omnifarious; 06.12.2010
comment
Я думаю, что я пытался сказать, что всегда можно утверждать, что никогда не нужно ничего более высокого уровня, чем ASM. Члены комитета всегда были чрезмерно консервативны, и усовершенствования языка происходили очень медленно. Большинство поставщиков внедрили нестандартное расширение ключевого слова свойства в той или иной форме, но стандарт до сих пор не догнал. ИМХО, я не думаю, что комитет добился правильного баланса. - person Zach Saw; 06.12.2010
comment
Следует также отметить, что из-за того, что эта группа состоит из людей с разными (деловыми) интересами, традиционно было чрезвычайно трудно достичь консенсуса по о чем бы то ни было. - person Zach Saw; 06.12.2010
comment
@Zach Saw - я считаю, что в C ++ 0x есть «атрибуты» функций и классов. И я думаю, что это соответствует определению ключевого слова «собственность». - person Omnifarious; 06.12.2010
comment
@Omni: Нет, это совершенно разные вещи. Однако существует предлагаемое решение для свойств в C++0x, но оно называется неявно вызываемыми функциями (или ICF) и неявно вызываемыми функциями-членами (ICMF). Не уверен, что он был исключен из С++ 0x. - person Zach Saw; 07.12.2010
comment
@Zach: Эти функции не являются устаревшим персоналом. Напротив, функции C++ были тщательно отобраны, чтобы быть достаточно общими, чтобы они не стали устаревшими в обозримом будущем. - person Yakov Galka; 13.12.2010
comment
@ybungalobill: Это моя точка зрения. Они слишком осторожны. Чтобы убедиться, что функции не станут устаревшими в обозримом будущем, сам язык станет устаревшим. - person Zach Saw; 19.01.2011
comment
У меня небольшие проблемы с пониманием всей этой using {} штуки. Это идея функции, а не действующая в настоящее время конструкция C++, верно? @ZachSaw, почему ты принял этот ответ, если это не то, что ты ищешь? - person Kyle Strand; 11.03.2015
comment
@KyleStrand - это идея будущего, а не действующая в настоящее время конструкция C ++, да. Если бы я мог говорить за Зака, я бы сказал, что он принял это, потому что это вызвало самое интересное обсуждение в комментариях и в сочетании с комментариями объяснило, как и почему функции добавляются в C++. - person Omnifarious; 11.10.2017

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

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;
person Timo    schedule 06.12.2010
comment
Пожалуйста, внимательно прочитайте вопрос, прежде чем отвечать. - person Zach Saw; 06.12.2010
comment
Я видел это. Но вопрос немного бессмысленный, потому что на него, скорее всего, нет ответа. Многие вещи в стандарте С++ не имеют смысла. - person Timo; 06.12.2010
comment
Иногда ответ на вопрос, почему X не разрешен? заключается в том, что C++ предоставляет другой способ достижения того же самого — как показано здесь. - person Brent Bradburn; 06.11.2013
comment
Это то, над чем я пытался работать, считается ли это плохой практикой или нет. Кажется, люди говорят, что не используют using namespace в заголовке, но мне интересно, имеют ли они в виду глобальное пространство. Можно ли использовать using std:vector внутри заголовка внутри вашего собственного пространства имен перед объявлением класса, использующего множество векторов? - person thomthom; 16.12.2013
comment
Побочным эффектом этого является то, что пользователю Foo необходимо знать, что он находится в пространстве имен detail, тогда как Foo требуется полная квалификация для разрешения неоднозначностей (::Foo). Так что нет, здесь продемонстрировано не достижение того же самого. - person Zach Saw; 06.03.2014
comment
@thomthom Проблема с наличием директив использования внутри заголовка заключается в том, что любой исходный файл, который включает этот заголовок, или любой исходный файл, который включает в себя любой другой файл, включающий этот заголовок, также содержит эти директивы использования, вполне возможно, без автор исходного файла, даже зная об этом. Если он ограничен по объему, например, помещен в отдельное пространство имен, то это не такая большая проблема. - person Justin Time - Reinstate Monica; 01.07.2016

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

namespace MyScope = System::Network::Win32::Sockets;
person nemethpeter    schedule 06.12.2010
comment
С таким количеством пространств имен для псевдонимов (плюс тот факт, что вы не можете охватить псевдоним), вы скоро столкнетесь с той же проблемой, что и глобальное использование пространства имен. - person Zach Saw; 06.12.2010
comment
@Zach Saw - Вы проверили, чтобы убедиться, что они не могут быть ограничены областью действия? - person Omnifarious; 06.12.2010
comment
MSVC2010 не позволяет этого. C++Builder2010 тоже нет. - person Zach Saw; 06.12.2010
comment
@Zach Saw - g++ 4.5.1 позволяет ограничить его областью действия. Но это не может быть ограничено рамками класса. Хм... Это не так полезно. - person Omnifarious; 06.12.2010
comment
Так что ни один компилятор не позволяет этого. Кто проголосовал за этот ответ??? - person Zach Saw; 06.12.2010
comment
Я думаю, вам нужно переназначить вложенные пространства имен на одно, два или три глубоких. - person nemethpeter; 09.12.2010

Вы можете использовать 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);
};
person Declan    schedule 04.03.2014
comment
В этом случае вы в конечном итоге определите все типы в пространстве имен System::Network::Win32::Sockets, используемом в классе. Мало того, вам также придется определять все типы в других пространствах имен, используемых в этом классе! Вы понимаете, что это непрактично, не так ли? И в файле CPP вам все равно придется полностью определять типы. - person Zach Saw; 05.03.2014
comment
Вы конечно правы. Но это не обязательно плохо. Обычно в любом случае не хочется (или не следует) использовать полное пространство имен, а скорее определенные идентификаторы (например, Handle). И да, это немного утомительно, когда приходится печатать дополнительно, как если бы писать с использованием System::Network::Win32::Sockets::Handle. Но это не значит, что лучше писать с использованием System::Network ::Win32::Sockets просто потому, что меньше печатается. Это компромисс между мелкозернистым контролем/четкостью и большим количеством текста. - person Declan; 06.03.2014
comment
Исправление: предпочитайте писать с использованием System::Network::Win32::Sockets. И в файле .cpp обычно можно использовать все пространство имен (и избегать повторения typedefs), поскольку оно не будет включено в другие заголовки и загрязнит глобальный пространство имен - person Declan; 06.03.2014
comment
Не думайте, что все дело в лени программиста. Печатать больше — это наименьшая из моих забот. Определение такого количества типов в каждом классе делает код чрезвычайно многословным. Читабельность страдает. - person Zach Saw; 06.03.2014
comment
да. И сделать все в пространстве имен доступным, когда вам все это не нужно, подвержено ошибкам и загрязняет текущее пространство имен. Вам нужно только указать нужные идентификаторы, которых обычно не так много. Как я уже сказал, это компромисс. Больше контроля с большим количеством текста или наоборот. - person Declan; 09.03.2014

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

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

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

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

person Ichimonji10    schedule 06.12.2010
comment
Анонимное пространство имен является локальным для единицы перевода, а не для файла. Это означает, что имена в анонимном пространстве имен доступны для всех других файлов, которые являются частью этих единиц перевода, даже если они являются другими файлами заголовков. Это может незаметно изменить значение случайных заголовочных файлов. - person Omnifarious; 06.12.2010
comment
Неоднозначности можно разрешить как обычно или с помощью псевдонима пространства имен. Так что весь ваш аргумент спорный. Кроме того, ваше безымянное пространство имен также не ограничено областью действия - это очень плохо. - person Zach Saw; 06.12.2010