C ++ 17 можно ли принудительно установить квалифицированный доступ к переменным из функций в том же пространстве имен? - PullRequest
1 голос
/ 27 сентября 2019

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

// file qqq.cpp

namespace aaa {
    void f();
    int x; 
}

void aaa::f() {
    aaa::x;       // 0. INTENDED ACCESS to x in namespace aaa (also works)
    x;            // 1. SURPRISE: x can be accessed without aaa:: qualification
    bool x;       // 2. SURPRISE: given (1) why is it allowed to redefine x?
}

вопрос:

A) естьЛюбой способ обеспечить, чтобы все объекты в пространстве имен были слепыми по отношению к другим составляющим, и требовать доступа всегда через ::?

B), если нет, какова была бы правильная практика кодирования для получения желаемого поведения?

C) в противном случае альтернативным решением было бы разделить каждое пространство имен на 2, одно для функций и другое для переменных, таких как f_aaa и v_aaa.но это кажется довольно неуклюжим и уродливым в практическом использовании, например.void f_sqlite :: myfun () {v_sqlite :: myvar;} вместо просто void sqlite :: myfun () {sqlite :: myvar;}


edit 1: контекст, «проблема», которую я пытаюсь решить:

рефакторинг нескольких тысяч строк кода, пространства имен считались подходящими для объединения связанных элементов, например.пространство имен sqlite для служебных функций и переменных sqlite, используемых в базе кода.принудительный доступ через :: был бы отличным способом повышения ясности и избежания конфликтов имен и сокрытия.отдельные пространства имен для «одного пакета» победили бы цель.классы не кажутся концептуально подходящими.

edit 2:

D) возможно ли получить ПРЕДУПРЕЖДЕНИЕ (включить флаг компилятора), чтобы сигнализировать, когда функция в пространстве имен aaa обращается к переменной в пространстве имен aaaбез квалификации?

edit 3:

Я думаю, что я все равно буду использовать «отдельные пространства имен», но с помощью вложенных пространств имен

// file qqq.cpp

namespace aaa::f { // namespace for functions
    void f();
    void g();
}

namespace aaa::v { // namespace for variables
    int x;
}

// definition of function f inside namespace aaa::f

void aaa::f::f() {
    aaa::v::x;    // only way of accessing x in aaa::v (good) (ugly)
    x;            // compiler error (good)
    bool x;       // normal scope hiding (good)
    g();          // works: ARGH! would like to force qualifying with aaa::f::
}

все еще довольно уродливо, хотя,а также!функции могут по-прежнему вызывать друг друга без оговорок, объекты могут по-прежнему вызывать / ссылаться друг на друга без определения.было бы неплохо просто иметь возможность использовать некоторый «принудительный квалификатор» (например, «приватный») для всех или некоторых элементов внутри пространства имен.

Ответы [ 2 ]

1 голос
/ 28 сентября 2019

Использование отдельного (вложенного) пространства имен для функции и переменной не очень хорошая идея.Это делает код менее читабельным.

Также всегда квалифицировать все имена излишне.Если функция f находится в пространстве имен aaa, то ей действительно следует отдавать предпочтение переменным из этого пространства имен.

И, наконец, единственная причина, по которой у вас возникнет такая проблема, заключается в том, что вы используете слишком много глобальных переменных (илидлинные функции), что на самом деле является плохой практикой, потому что это усложняет поддержку кода.

Итак Я рекомендую вам использовать хорошие методы кодирования , например

  • маленькие функции (меньше экрана)
  • избегайте глобальных переменных
  • объектно-ориентированное проектирование с использованием класса с функциями-членами и данными, когда это необходимо.
  • маленькие файлы (так что вы нене получите ненужных вещей)
  • избегайте переменных в заголовочных файлах
  • включайте только те файлы, которые вам действительно нужны (таким образом, вы не получите много конфликтов, если таковые имеются)

На самом деле, если у вас действительно есть проблема, это потому, что текущий код большой и не следует передовым методам ..

Другие обходные пути в комментариях и ответах migОн работает, но лучше проверить, соответствует ли ваш дизайн требованиям, и соответствующим образом изменить код.

Дополнительные баллы:

Еще одна вещь, которая может вызвать много неясностей, - это использоватьбазовый тип данных, когда вы действительно должны использовать пользовательские типы.

  • Использует типизированное перечисление (enum class), когда вы хотите использовать некоторую константу для определенного параметра вместо define или целых чисел.
  • Использует класс или структуру, если у вас есть данные, которые объединены вместе и используются во всем приложении.
  • Если вы используете функции шаблона, вы можете тщательно продумать, какие типы данных они допускают, особенно если выимеют общее имя, например open для функции.
1 голос
/ 27 сентября 2019

A) есть ли какой-нибудь способ запретить всем объектам в пространстве имен быть незаметными по отношению к своим собратьям и требовать доступа всегда через ::?

Нет.

B) если нет, какова будет правильная практика кодирования для получения желаемого поведения?

Используйте class.

C) если нет, альтернативным решением было бы разделить пространство имен aaa на 2, одно для функций, а другое для переменных, таких как f_aaa и v_aaa.но это кажется довольно неуклюжим и уродливым в практическом использовании, например.void f_sqlite :: myfun () {v_sqlite :: myvar;} вместо просто void sqlite :: myfun () {sqlite :: myvar;}

Используйте class для группировки соответствующих функций и данных.То, что вы хотите скрыть, поместите в секцию private.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...