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

Отменить include файлы в С++

Предположим, что у меня есть следующий код (буквально) в исходном файле С++:

// #include <iostream> // superfluous, commented-out
using std::cout;
using std::endl;

int main()
{
    cout << "Hello World" << endl;
    return 0;
}

Я могу скомпилировать этот код, даже если #include <iostream> закомментирован:

g++ -include my_cpp_std_lib_hack source.cpp

Где my_cpp_std_lib_hack - это файл в некотором центральном месте, который включает в себя все файлы стандартной библиотеки С++:

#include <ciso646>
#include <climits>
#include <clocale>
...
#include <valarray>
#include <vector>

Конечно, я могу использовать правильные параметры компиляции для всех компиляторов, которым я забочусь (это MS Visual Studio и, возможно, несколько других), и я также использую предварительно скомпилированные заголовки.

Использование такого взлома дает мне следующие преимущества:

  • Быстрая компиляция (поскольку вся стандартная библиотека предварительно скомпилирована)
  • Не нужно добавлять #include, когда все, что я хочу, добавляет некоторый вывод отладки
  • Не нужно запоминать или искать все время, когда объявлен черт std::max
  • Чувство, что STL волшебным образом встроен в язык

Так что я удивляюсь: я делаю что-то очень неправильное здесь?

Будет ли этот хак сломаться при написании больших проектов?

Может быть, все остальные уже используют это, и никто мне не сказал?

4b9b3361

Ответ 1

Единственное, что "неправильно" заключается в том, что вы полагаетесь на флаг командной строки для компилятора, чтобы файлы были скомпилированы. Вам нужно будет сделать что-то другое, если не использовать GCC. Большинство компиляторов, вероятно, предоставляют эквивалентную функцию, но лучше всего писать переносимый исходный код, а не излишне полагаться на функции вашей конкретной среды сборки.

Другим программистам не нужно ломать голову над файлами Makefile (или Ant или рабочими пространствами Eclipse или что-то еще), чтобы выяснить, как все работает.

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

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

Ответ 2

Так что я удивляюсь: я делаю что-то очень неправильное здесь?

Да. Конечно, ваши заголовки предварительно скомпилированы, но компилятор все равно должен делать такие вещи, как поиск имен по всей включенной массе вещей, что замедляет компиляцию.

Будет ли этот хак сломаться при написании больших проектов?

Да, это в значительной степени проблема. Кроме того, если кто-то еще смотрит на этот код, им будет интересно, откуда пришел std::cout (ну, предположим, что пользовательский тип). Без #include они ничего не поймут.

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

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

Ответ 3

Забудьте об ускорении компиляции - предварительно скомпилированный заголовок с шаблонами на самом деле не "предварительно скомпилирован", за исключением имени и синтаксического анализа, насколько я слышал. Я не буду верить в скорость компиляции, пока не увижу ее в тестах.:)

Что касается полезности:

Я предпочитаю иметь IDE, который обрабатывает мои включенные для меня (это все еще плохо для С++, но Eclipse уже добавляет, что известный включает в себя ctrl + shift + n с... ну, допустимая надежность:)).

Ответ 4

Выполнение "подпольных" включений, как и это, также затрудняет тестирование. Вы хотите скомпилировать наименьшее возможное подмножество кода при тестировании конкретного компонента. Выяснить, что это подмножество будет сложно, если заголовки/источники не будут честны в отношении их зависимостей, поэтому вы, вероятно, просто перетащите свой my_cpp_std_lib_hack в каждый unit test. Это увеличит время компиляции для ваших тестовых наборов. У установленных кодовых баз часто более чем в три раза больше тестового кода, чем обычный код, поэтому это может стать проблемой, поскольку ваша база кода растет.

Ответ 5

Из руководства GCC:

-include file

Обработать файл, как будто #include "file" появился как первая строка файл первичного источника. Однако поиск первой папки в файле рабочий каталог препроцессора вместо каталога, содержащего основного исходного файла. Если не найдено там, его ищут в остаток от #include "..." search как обычно.

Итак, что вы делаете, по сути, эквивалентно началу каждого файла с помощью строки

#include "my_cpp_std_lib_hack"

что делает Visual Studio при сборе обычно включенных файлов в stdafx.h. Для этого есть некоторые преимущества, о чем свидетельствуют другие, но ваш подход скрывает это в процессе сборки, так что никто, кто смотрел прямо на один из ваших исходных файлов, не узнает об этой скрытой магии. Таким образом, ваш непрозрачный код не кажется мне хорошим стилем, поэтому, если вы увлечены всеми прекомпилированными преимуществами заголовка, я предлагаю вам явно включить ваш файл взлома.

Ответ 6

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

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

Ответ 7

Мы стараемся не включать неиспользуемые или даже редко используемые вещи, например, в VС++ есть

#define WIN32_LEAN_AND_MEAN //exclude rarely used stuff

и то, что мы ненавидим в MFC, заключается в том, что если вы хотите создать простую программу u, вы получите большой исполняемый файл со всей библиотекой (если он статически связан), поэтому не очень хорошо, если вы хотите использовать только cout а другой нет?

еще одна вещь, которая мне не нравится передавать аргументы через командную строку coz, я могу оставить проект на некоторое время и забыть, какие аргументы... например. я предпочитаю использовать

#pragma (comment, "xxx.lib")

чем использовать его в командной строке, он напоминает мне хотя бы о том, какой файл я хочу

Это мое собственное мнение делает ваш код стабильным и легким для компиляции, чтобы гнить, поскольку гниение кода - очень неприятная вещь!!!!!