Как автоматически включить все заголовки в каталог - PullRequest
9 голосов
/ 12 марта 2010

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

Сейчас у меня есть один main.cpp файл со следующим:

#include "e0614.h"
int main()
{
    E0614 ex;
    ex.solve();
}

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

Итак, мои вопросы:

  1. Могу ли я включить все заголовки в каталог, чтобы, по крайней мере, мне не пришлось менять строку #include?
  2. Еще лучше, могу ли я переписать свое решение, чтобы мне даже не нужно было нажимать main.cpp, не имея одного файла со всем кодом для каждого упражнения в нем?

Обновление:

В итоге я последовал совету Пойты и сгенерировал main.cpp с помощью скрипта .

Поскольку я использую IDE (Visual Studio), я хотел, чтобы это было интегрировано с ним, поэтому я провел небольшое исследование о том, как это сделать. Для тех, кто интересуется, читайте дальше (это было честно, но не совсем просто).

Visual Studio позволяет использовать внешний инструмент через меню Инструменты -> Внешние инструменты и содержит набор предопределенных переменных, таких как $(ItemFileName), которые могут быть переданы в инструмент. Поэтому в этом примере я использовал простой командный файл, и ему передается имя выбранного в данный момент файла в Visual Studio.

Чтобы добавить этот инструмент на панель инструментов, щелкните правой кнопкой мыши на панели инструментов, выберите «Настройка» -> «Команды» -> «Инструменты», выберите «Внешняя команда X» и перетащите его на панель инструментов. Замените X номером, соответствующим инструменту, который вы создали. Моя установка содержала 5 предварительно существующих инструментов по умолчанию, перечисленных в разделе «Инструменты» -> «Внешние инструменты», поэтому я создал инструмент номер 6. Вы должны выяснить это число, так как оно не показано. Затем вы можете назначить иконку ярлыку (это команда BuildMain, показанная ниже):

alt text

Ответы [ 10 ]

14 голосов
/ 12 марта 2010
  1. Нет. Вы должны включить их все, если это то, что вы хотите сделать.

  2. Нет. По крайней мере, не таким образом, чтобы сохранить набор текста.

Конечно, вы можете написать скрипт для создания main.cpp для вас ...

9 голосов
/ 12 марта 2010

Если вы строите свой код, используя make, вы сможете это сделать.

Могу ли я включить все заголовки в каталог, чтобы, по крайней мере, мне не пришлось менять строку #include?

Измените строку включения на что-то вроде #include <all_headers.h>. Теперь вы можете позволить вашему Makefile автоматически сгенерировать all_headers.h с целью вроде:

all_headers.h:
    for i in `ls *.h`; do echo "#include <$i>" >>all_headers.h; done

Убедитесь, что all_headers.h удаляется, когда вы «очищаете».

Еще лучше, могу ли я переписать свое решение, чтобы мне даже не нужно было трогать main.cpp, без одного файла со всем кодом для каждого упражнения в нем?

Вы можете сделать это, если абстрагируете свой класс с помощью typedef. В вашем примере измените имя класса с E0614 на myClass (или что-то еще). Теперь добавьте строку в ваш Makefile под циклом for выше, где написано echo "typedef "$MY_TYPE" myClass;" >>all_headers.h. Когда вы собираете свою программу, вызовите make с чем-то вроде make MY_TYPE=E0614, и ваш typedef будет автоматически заполнен классом, который вы хотите проверить.

3 голосов
/ 12 марта 2010

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

ln -s e0615.h последний.ч

и назовите свой класс E вместо E0614, конечно

P.S. Насколько я знаю, вы не можете сделать #include xxx*

1 голос
/ 12 марта 2010

Не используйте один main.cpp, который вы модифицируете для каждого упражнения. В этом решении используются встроенные правила make, поэтому вам нужно всего лишь набрать make e0614, и он сгенерирует e0614.cpp, скомпилирует и скомпонует его. Вы можете настроить каждый файл .cpp (они не будут регенерированы, как написано ниже) и сохранить всю эту историю, чтобы ссылаться на нее по мере выполнения упражнений, а не стирать ее при переходе от одного к следующему , (Вы также должны использовать контроль источников, например Mercurial .)

Makefile

e%.cpp:
        ./gen_ex_cpp $@ > $@

Вы можете генерировать стандартный код с помощью скриптов, потому что вы не хотите, чтобы он также был утомительным. Для этих сценариев есть несколько вариантов & mdash; и я использую разные языки, включая C ++, Python и shell & mdash; но нижеприведенный Python короткий и должен быть простым и понятным.

Пример скрипта генерации

#!/usr/bin/python
import sys
args = sys.argv[1:]
if not args:
  sys.exit("expected filename")
name = args.pop(0).partition(".")[0]
if args:
  sys.exit("unexpected args")
upper_name = name.upper()
print """
#include "%(name)s.hpp"
int main() {
  %(upper_name)s ex;
  ex.solve();
  return 0;
}
""" % locals()
0 голосов
/ 13 марта 2010

Почему бы не использовать объектные механизмы?

Вы можете использовать для этого стратегию Exemplar.

class BaseExercise
{
public:
  static bool Add(BaseExercise* b) { Collection().push_back(b); return true; }
  static size_t Solve() {
    size_t nbErrors = 0;
    for(collections_type::const_iterator it = Collection().begin(), end = Collection().end(); it != end; ++it)
      nbErrors += it->solve();
    return nbErrors;
  }

  size_t solve() const
  {
    try {
      this->solveImpl();
      return 0;
    } catch(std::exception& e) {
      std::cout << mName << " - end - " << e.what() << std::endl;
      return 1;
    }
  }
protected:
  explicit BaseExercise(const char* name): mName(name)
  {
  }
private:
  typedef std::vector<BaseExercise*> collection_type;
  static collection_type& Collection() { collection_type MCollection; return MCollection; }

  virtual void solveImpl() const = 0;

  const char* mName;
}; // class BaseExercise

template <class T>
class BaseExerciseT: public BaseExercise
{
protected:
  explicit BaseExerciseT(const char* b): BaseExercise(b) { 
    static bool MRegistered = BaseExercise::Add(this);
  }
};

Хорошо, это основа.

// Exercise007.h
#include "baseExercise.h"

class Exercise007: public BaseExerciseT<Exercise007>
{
public:
  Exercise007(): BaseExerciseT<Exercise007>("Exercise007") {}
private:
  virtual void solveImpl() const { ... }
};

// Exercise007.cpp
Exercise007 gExemplar007;

И дляmain

// main.cpp
#include "baseExercise.h"

int main(int argc, char* argv[])
{
  size_t nbErrors = BaseExercise::Solve();
  if (nbErrors) std::cout << nbErrors << " errors" << std::endl;
  return nbErrors;
}

И здесь вам не нужен скрипт;)

0 голосов
/ 12 марта 2010
sed -i 's/\<\\([eE]\\)[0-9]+\\>/\19999/' main.cpp

Заменить 9999 на нужный номер. Там могут быть лучшие способы.

0 голосов
/ 12 марта 2010

написание правила make-файла для передачи имени исполняемого файла в качестве параметра -DHEADERFILE = что-то компилятору не должно быть сложным. Что-то вроде:

%.exe : %.h %.cpp main.cpp
    gcc -o $< -DHEADER_FILE=$<F $>

OTOH, я не знаю, выполняет ли #include макрос для имени файла.

0 голосов
/ 12 марта 2010

попробуйте это: -

#ifndef a_h
#define a_h

#include <iostream>
#include <conio.h>
#incl....as many u like
class a{
f1();//leave it blank
int d;
}
#endif //save this as a.h

позже включите это в основную программу ur, которая является файлом cpp

#include "a.h"

... вашей программой

0 голосов
/ 12 марта 2010

Вы можете использовать условную компиляцию для имени класса с помощью конкатенации.

// Somewhere in your other files
define CLASS_NUMBER E0614

// in main.cpp
#define ENTERCLASSNUMBER(num) \
##num## ex;

// in main()
ENTERCLASSNUMBER(CLASS_NUMBER)

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

0 голосов
/ 12 марта 2010

Создайте основной включаемый файл, содержащий имена всех заголовков, которые вы хотите.

Включать * это действительно плохая идея, даже если бы вы могли.

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