代码之家  ›  专栏  ›  技术社区  ›  JRL

如何自动包含目录中的所有标题

  •  9
  • JRL  · 技术社区  · 14 年前

    我正在练习一本C++的练习题。对于每一个练习,我都想尽量减少我必须编写的样板代码。我已经以某种方式设置了我的项目,但它似乎不正确,并且需要太多的更改。

    现在我有一个 main.cpp 文件如下:

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

    每次我从练习中创建一个新类时,我都必须来修改这个文件以更改包含的头的名称以及我正在实例化的类。

    所以我的问题是:

    1. 我可以包含目录中的所有标题,这样至少我不必更改 #include 线路?
    2. 更好的是,我能重写我的解决方案,这样我就不必碰 主CPP ,而不是一个包含所有代码的文件?

    更新:

    最后我听从了波塔的建议 通过脚本生成main.cpp .

    由于我使用的是ide(visual studio),所以我希望将它与之集成,所以对如何集成做了一些研究。对于那些对如何做感兴趣的人,请继续阅读(这是公平的,但不是完全的,直接的)。

    visual studio允许您通过“工具”->“外部工具”菜单使用外部工具,并包含一系列预定义的变量,例如 $(ItemFileName ,可以传递给工具。所以在这个例子中,我使用了一个简单的批处理文件,它被传递到visual studio中当前所选文件的名称。

    若要将该工具添加到工具栏,请在工具栏上单击鼠标右键,选择“自定义”->“命令”->“工具”,然后选择“外部命令X”并将其拖到工具栏上。用与您创建的工具对应的数字替换X。我的安装包含“工具”->“外部工具”中列出的5个默认预先存在的工具,因此我创建的工具是6号工具。你得弄清楚这个号码,因为它没有显示出来。然后可以为快捷方式指定一个图标(这是下面显示的buildmain命令):

    alt text http://img691.imageshack.us/img691/4853/capturerg.png

    10 回复  |  直到 14 年前
        1
  •  14
  •   Peter Alexander    14 年前
    1. 不。如果你想这么做的话,你必须把它们都包括在内。

    2. 不。至少,在某种程度上不会节省打字时间。

    当然,您可以编写一个脚本来为您创建main.cpp…

        2
  •  9
  •   bta    14 年前

    如果您使用 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
    

    确保 所有邮件头.h 当你“清理”时被删除。

    更好的是,我可以重写我的解决方案,这样我甚至不必接触main.cpp, 没有一个包含所有代码的文件?

    如果你用一个 typedef . 在您的示例中,将类名从 E0614 myClass (或者别的)。现在,在makefile的下面添加一行 for 上面的圈表示 echo "typedef "$MY_TYPE" myClass;" >>all_headers.h . 当你构建你的程序时,调用make make MY_TYPE=E0614 您的typedef将自动填入您要测试的类。

        3
  •  3
  •   DVK    14 年前

    如果你在unix系统上,你可以有一个指向最新练习的软链接。

    LN-S e0615.h最新.h

    当然,把你的E类命名为e0614

    据我所知,你不能 #include xxx*

        4
  •  1
  •   Roger Pate    14 年前

    不要使用为每个练习修改的main.cpp。此解决方案使用make的内置规则,因此您只需键入 make e0614 它将生成e0614.cpp,编译并链接它。您可以自定义每个 CPP 文件(它们不会像下面写的那样重新生成)并维护所有历史记录,以便在完成练习时引用,而不是在从一个文件移到下一个文件时将其删除。(您还应该使用源代码管理,例如 Mercurial )

    生成文件

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

    您可以用脚本生成样板代码,因为您也不希望它太乏味。这些脚本有多种选择,我使用多种语言,包括C++、Python和shell,但下面的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()
    
        5
  •  0
  •   ddyer    14 年前

    创建一个主包含文件,其中包含所需的所有标题的名称。

    即使你可以的话,把*也包括进去真是个坏主意。

        6
  •  0
  •   Nathan Osman    14 年前

    可以通过使用连接对类名使用条件编译。

    // Somewhere in your other files
    define CLASS_NUMBER E0614
    
    // in main.cpp
    #define ENTERCLASSNUMBER(num) \
    ##num## ex;
    
    // in main()
    ENTERCLASSNUMBER(CLASS_NUMBER)
    

    但不知道其中包括什么。如上所述,脚本可能是最好的选择。

        7
  •  0
  •   Ben Voigt    14 年前

    编写makefile规则以将可执行文件的名称作为-dheaderfile=something参数传递给编译器一点都不难。类似于:

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

    哦,我不知道include是否对文件名进行了宏扩展。

        8
  •  0
  •   Peter Alexander    14 年前
    sed -i 's/\<\\([eE]\\)[0-9]+\\>/\19999/' main.cpp
    

    将9999替换为所需号码。也许有更好的办法。

        9
  •  0
  •   Matthieu M.    14 年前

    为什么不使用对象机制?

    你可以使用一个范例策略。

    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.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;
    }
    

    在这里,你不需要任何脚本;)

        10
  •  -1
  •   comfreak    14 年前

    试试这个:

    #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
    

    后来 在cpp文件的主程序中包括这个

    #include "a.h"
    

    …你的程序