Подтвердить что ты не робот

Как выбрать единую перегрузку функции с помощью namespace:: function в С++?

рассмотрим следующий код на С++.

namespace A {
    void f() { // first function
    }

    void f(int) { // second function
    }
}
...
using A::f; // introduces both functions

Есть ли способ ввести только одну функцию?

4b9b3361

Ответ 1

Это поведение четко определено в стандарте.

C++03 7.3.3 The using declaration:

"... Если имя является именем перегруженной функции-члена, то все имена функций должны быть доступны.".

Ответ 2

using ключевое слово приведет все имена в текущую область. Так что с этим текущим кодом это невозможно.

Однако вы можете ввести имена частично в файл следующим образом:

namespace A {
  void f();  // declaration
}
using A::f;
// now only `A::f()` is visible in the subsequent code
// technically `A::f(int)` is not yet visible (thus unusable)

// introduce the other function later on
namespace A {
  void f(int);
}

Демо.

Edit: Способ лучше состоит в том, чтобы поместить A::f(int) внутри вложенного namesapce и ввести псевдоним (для удобства использования).

namespace A {
  void f();
  namespace Internal {
    void f(int);
  }
}
using A::f;
namespace A_ = A::Internal;

Теперь другая функция также может использоваться как A_::f(int).

Ответ 3

Не знаю, насколько я знаю. Вы можете написать функцию обертки, если это проблема.

void f(int i) { A::f(i); }

Ответ 4

Я приведу еще несколько примеров в дополнение к остальным ответам.

Многие книги для программирования на С++ часто выставляют все пространство имен STD, добавляя следующую строку где-то в начале исходного файла:

using namespace std;

Появление полного пространства имен фактически является плохой практикой в ​​реальной жизни из-за различных конфликтов, которые могут возникнуть в какой-то момент, особенно когда код предоставляется многими разработчиками, которые работают над одной и той же задачей. Такой стиль программирования также противоречит одному из основных правил объектно-ориентированного программирования - избегайте подвергать себя большему, чем это действительно необходимо, путем инкапсуляции ваших данных. Вот почему классы, например, имеют публичные и частные члены, геттеры и сеттеры и так далее. Пространства имен - это еще один способ группировки информации. Выявление всего пространства имен std противоречит этому правилу, особенно если вы хотите использовать let say только std:: cout, std:: cin и станд:: епсИ. Вы можете легко применить с помощью к определенным функциям, что позволит вам более точно контролировать и повысить вероятность избежать конфликтов имен в нескольких пространствах имен, которые вы могли бы использовать в какой-то момент:

using std::cout;
using std::cin;
using std::endl;

Это позволяет вам вызывать cout, cin и endl в коде без префикса пространства имен. Если в какой-то момент у вас возник конфликт с именами, гораздо проще посмотреть на набор с помощью -directives, а не на то, чтобы узнать, где во всем пространстве имен, которое вы обнаружили, возникает ошибка.

Люди также используют директиву с использованием для одной функции/переменной, если существует цепочка пространств имен или имя пространства имен слишком велико. Если у вас есть что-то вроде

namespace my_really_long_and_pointless_namespace_that_does_nothing_at_all {
    void foo() { ... }
}

или

namespace1 {
    namespace2 {
        ...
            namepaceN {
                void foo() { ... }
            }
    }
}

боль в прикладе должна писать всю вещь каждый раз, когда вы хотите вызвать метод foo(). Пишем

using my_really_long_and_pointless_namespace_that_does_nothing_at_all::foo;

и соответственно

using namespace1::namespace2:: ... ::namespaceN::foo;

вы пощадите свои пальцы какой-то работой.

Ответ 5

Попробуйте сделать это:

namespace A { 
    void f() { // first function 
    } }

using A::f; // introduces only above function

namespace A { 

    void f(int) { // second function 
    } 
} 

Ответ 6

Можно обернуть их в другую область:

namespace B { // Wrap the first function
    void f() { A::f(); }
}

namespace C { // Wrap the second function
    void f(int i) { A::f(i); }
}

int main(int argc, char *argv[])
{
    {
        using B::f; // Make the first function available
        f();
    } // Make the first function unavailable

    {
        using C::f; // Make the second function available
        f(0);
    } // Make the second function unavailable

    return 0;
}

Но я не думаю, что вы можете сделать это с помощью одного объявления using.

Ответ 7

С++ не имеет механизма для импорта одной конкретной функции перегрузки из пространства имен.

В качестве обходного пути вы можете обернуть вызов функции в локальную функцию:

static inline void f(int i) { A::f(i); }

Ключевое слово static очень важно -

  • Это уменьшает риск глобального загрязнения пространства имен для текущей единицы компиляции.
  • Это позволяет сделать это в нескольких единицах компиляции (и, следовательно, может быть помещен в файл заголовка).
  • Это позволяет компилятору преодолеть дополнительный вызов функции (не будет никакой разницы в сгенерированном коде между вызовами f() и A::f())
  • Если f никогда не вызывается, дополнительный код не будет создан