Использование Директивы C ++ Реализация

В Cесли я использую #include "someFile.h"препроцессор выполняет текстовый импорт, что означает, что содержимое someFile.h «скопировать и вставить» на #include линия. В C++, Здесь using директивы. Работает ли это аналогично #include, т.е. текстовый импорт пространства имен?

using namespace std; // are the contents of std physically inserted on this line?

Если это не так, то как using Директива выполнена.

0

Решение

using namespace X просто скажет компилятору «при поиске имени искать в X так же, как и в текущем пространстве имен». Это ничего не «импортирует». Существует множество различных способов реализовать это в компиляторе, но эффект заключается в том, что «все символы в X выглядят так, как будто они доступны в текущем пространстве имен».

Или, другими словами, это будет выглядеть так, как будто компилятор добавляет X:: перед символами при поиске символов (а также при поиске самого имени без пространства имен).

[Это довольно сложно, и я обычно избегаю этого, если у вас есть символ X::a и местное значение aили вы используете using namespace Y а также есть еще один символ Y::a, Я уверен, что стандарт C ++ говорит, что используется, но ОЧЕНЬ легко спутать себя и других, используя такие конструкции.]

В общем, я использую явные квалификаторы пространства имен для «всего», поэтому я редко использую using namespace ... вообще в моем собственном коде.

2

Другие решения

Нет. Это означает, что с этой строки вы можете использовать классы и функции из 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;
}
2

Ничто не «импортируется» в файл 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" считается плохой практикой?

1

Нет, #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 вместо этого мы не получаем обратно конфликт.

1
По вопросам рекламы [email protected]