В C
если я использую #include "someFile.h"
препроцессор выполняет текстовый импорт, что означает, что содержимое someFile.h
«скопировать и вставить» на #include
линия. В C++
, Здесь using
директивы. Работает ли это аналогично #include
, т.е. текстовый импорт пространства имен?
using namespace std; // are the contents of std physically inserted on this line?
Если это не так, то как using
Директива выполнена.
using namespace X
просто скажет компилятору «при поиске имени искать в X так же, как и в текущем пространстве имен». Это ничего не «импортирует». Существует множество различных способов реализовать это в компиляторе, но эффект заключается в том, что «все символы в X выглядят так, как будто они доступны в текущем пространстве имен».
Или, другими словами, это будет выглядеть так, как будто компилятор добавляет X::
перед символами при поиске символов (а также при поиске самого имени без пространства имен).
X::a
и местное значение a
или вы используете using namespace Y
а также есть еще один символ Y::a
, Я уверен, что стандарт C ++ говорит, что используется, но ОЧЕНЬ легко спутать себя и других, используя такие конструкции.]
В общем, я использую явные квалификаторы пространства имен для «всего», поэтому я редко использую using namespace ...
вообще в моем собственном коде.
Нет. Это означает, что с этой строки вы можете использовать классы и функции из std
пространство имен без std::
префикс. Это не альтернатива #include
, К сожалению, #include
все еще здесь, в C ++.
Пример:
#include <iostream>
int main() {
std::cout << "Hello "; // No `std::` would give compile error!
using namespace std;
cout << "world!\n"; // Now it's okay to use just `cout`.
return 0;
}
Ничто не «импортируется» в файл using
директивы. Все, что он делает, это предоставляет более короткие способы записи символов, которые уже существуют в пространстве имен. Например, следующее обычно не компилируется, если это первые две строки файла:
#include <string>
static const string s("123");
<string>
заголовок определяет std::string
, но string
это не одно и то же. Вы не определили string
как тип, так что это ошибка.
Следующий фрагмент кода (вверху другого файла) будут компилировать, потому что, когда вы пишете using namespace std
, вы говорите компилятору, что string
это приемлемый способ написать std::string
:
#include <string>
using namespace std;
static const string s("123");
Но следующее будет не обычно компилируется, когда он появляется вверху файла:
using namespace std;
static const string s("123");
и не будет этого:
using namespace std;
static const std::string s("123");
Это потому что using namespace
на самом деле не определяет никаких новых символов; это потребовало некоторого другого кода (такого как код, найденный в <string>
заголовок), чтобы определить эти символы.
Кстати, многие люди мудро скажут тебе не писать using namespace std
в любом коде. Вы можете очень хорошо программировать на C ++, даже не писать using namespace
за любой Пространство имен. Но это тема другого вопроса, на который дан ответ в Почему "используя пространство имен std" считается плохой практикой?
Нет, #include
еще работает именно так то же самое в C ++.
Чтобы понять using
сначала нужно понять пространства имен. Это способ избежать конфликтов символов, которые случаются в больших проектах C, когда становится трудно гарантировать, например, что две сторонние библиотеки не определяют функции с одинаковыми именами. В принципе, каждый может выбрать уникальный префикс, но я столкнулся с реальными проблемами с нестатическими символами компоновщика C в реальных проектах (я смотрю на вас, Oracle).
Так, namespace
позволяет группировать вещи, включая целые библиотеки, включая стандартную библиотеку. Это позволяет избежать конфликтов компоновщика и избежать двусмысленности в отношении того, какую версию функции вы получаете.
Например, давайте создадим библиотеку геометрии:
// geo.hpp
struct vector;
struct matrix;
int transform(matrix const &m, vector &v); // v -> m . v
и также использовать некоторые заголовки STL:
// vector
template <typename T, typename Alloc = std::allocator<T>> vector;
// algorithm
template <typename Input, typename Output, typename Unary>
void transform(Input, Input, Output, Unary);
Но теперь, если мы используем все три заголовка в одной программе, у нас есть два типа vector
, две функции называются transform
(хорошо, одна функция и шаблон функции), и трудно быть уверенным, что компилятор каждый раз получает правильную. Кроме того, трудно сказать компилятору, какой мы хотим, если он не может догадаться.
Итак, мы исправляем все наши заголовки, чтобы поместить их символы в пространства имен:
// geo.hpp
namespace geo {
struct vector;
struct matrix;
int transform(matrix const &m, vector &v); // v -> m . v
}
и также использовать некоторые заголовки STL:
// vector
namespace std {
template <typename T, typename Alloc = std::allocator<T>> vector;
}
// algorithm
namespace std {
template <typename Input, typename Output, typename Unary>
void transform(Input, Input, Output, Unary);
}
и наша программа может легко их различить:
#include "geo.hpp"#include <algorithm>
#include <vector>
geo::vector origin = {0,0,0};
typedef std::vector<geo::vector> path;
void transform_path(geo::matrix const &m, path &p) {
std::transform(p.begin(), p.end(), p.begin(),
[&m](geo::vector &v) -> void { geo::transform(m,v); }
);
}
Теперь, когда вы понимаете пространства имен, вы также можете видеть, что имена могут быть довольно длинными. Таким образом, чтобы сохранить ввод полного имени везде, using
Директива позволяет вам вводить отдельные имена или целое пространство имен в текущую область.
Например, мы могли бы заменить лямбда-выражение в transform_path
вот так:
#include <functional>
void transform_path(geo::matrix const &m, path &p) {
using std::transform; // one function
using namespace std::placeholders; // an entire (nested) namespace
transform(p.begin(), p.end(), p.begin(),
std::bind(geo::transform, m, _1));
// this ^ came from the
// placeholders namespace
// ^ note we don't have to qualify std::transform any more
}
и это только влияет на эти символы в рамках этой функции. Если другая функция выберет geo::transform
вместо этого мы не получаем обратно конфликт.