简体   繁体   English

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

[英]How to auto-include all headers in directory

I'm going through exercises of a C++ book. 我正在阅读C ++书籍的练习。 For each exercise I want to minimize the boilerplate code I have to write. 对于每个练习,我想最小化我必须编写的样板代码。 I've set up my project a certain way but it doesn't seem right, and requires too many changes. 我以某种方式设置了我的项目,但它似乎不对,需要进行太多更改。

Right now I have a single main.cpp file with the following: 现在我有一个main.cpp文件,其中包含以下内容:

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

Each time I create a new class from an exercise, I have to come and modify this file to change the name of the included header as well as the class i'm instantiating. 每次我从练习中创建一个新类时,我都必须修改此文件以更改包含的标题的名称以及我正在实例化的类。

So my questions are: 所以我的问题是:

  1. Can I include all headers in the directory so at least I don't have to change the #include line? 我可以在目录中包含所有标题,这样至少我不需要更改#include行吗?
  2. Better yet, can I rewrite my solution so that I don't even have to touch main.cpp , without having one file with all the code for every exercise in it? 更好的是,我可以重写我的解决方案,这样我甚至不必触及main.cpp ,而没有一个文件包含每个练习的所有代码吗?

Update: 更新:

I ended up following Poita_'s advice to generate main.cpp via a script . 我最终遵循Poita_的建议, 通过脚本生成main.cpp

Since I'm using an IDE (Visual Studio), I wanted this integrated with it, so did a bit of research on how. 由于我使用的是IDE(Visual Studio),我希望将其与它集成,因此对其进行了一些研究。 For those interested in how, read on (it was fairly, but not entirely, straightforward). 对于那些对如何感兴趣的人,请继续阅读(这是公平的,但并非完全,直截了当)。

Visual Studio lets you use an external tool via the Tools -> External Tools menu, and contains a bunch of pre-defined variables, such as $(ItemFileName ), which can be passed on to the tool. Visual Studio允许您通过工具 - >外部工具菜单使用外部工具,并包含一组预定义的变量,例如$(ItemFileName ),可以传递给工具。 So in this instance I used a simple batch file, and it gets passed the name of the currently selected file in Visual Studio. 所以在这个例子中我使用了一个简单的批处理文件,它在Visual Studio中传递了当前所选文件的名称。

To add that tool to the toolbar, right click on the toolbar, select Customize -> Commands -> Tools, and select the "External Command X" and drag it to the toolbar. 要将该工具添加到工具栏,请右键单击工具栏,选择“自定义” - >“命令” - >“工具”,然后选择“外部命令X”并将其拖动到工具栏。 Substitute X with the number corresponding to the tool you created. 用与您创建的工具对应的数字替换X. My installation contained 5 default pre-existing tools listed in Tools -> External Tools, so the one I created was tool number 6. You have to figure out this number as it is not shown. 我的安装包含工具 - >外部工具中列出的5个默认预先存在的工具,因此我创建的工具是工具编号6.您必须弄清楚这个数字,因为它没有显示。 You can then assign an icon to the shortcut (it's the BuildMain command shown below): 然后,您可以为快捷方式指定一个图标(它是下面显示的BuildMain命令):

替代文字

  1. No. You have to include them all if that's what you want to do. 不,如果你想做的话,你必须把它们全部包括在内。

  2. No. At least, not in a way that's actually going to save typing. 不,至少,不是一种实际上会节省打字的方式。

Of course, you could write a script to create main.cpp for you... 当然,您可以编写一个脚本来为您创建main.cpp ...

If you build your code using make , you should be able to do this. 如果使用make构建代码,则应该能够执行此操作。

Can I include all headers in the directory so at least I don't have to change the #include line? 我可以在目录中包含所有标题,这样至少我不需要更改#include行吗?

Change your include line to something like #include <all_headers.h> . 将您的包含行更改为#include <all_headers.h> Now, you can let your Makefile auto-generate all_headers.h with a target like: 现在,您可以让Makefile自动生成all_headers.h ,其目标如下:

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

Make sure that all_headers.h is getting deleted when you 'make clean'. 确保在“干净”时删除all_headers.h

Better yet, can I rewrite my solution so that I don't even have to touch main.cpp, without having one file with all the code for every exercise in it? 更好的是,我可以重写我的解决方案,这样我甚至不必触及main.cpp,而没有一个文件包含每个练习的所有代码吗?

You can do this if you abstract away your class with a typedef . 如果使用typedef抽象出类,则可以执行此操作。 In your example, change your class name from E0614 to myClass (or something). 在您的示例中,将您的类名从E0614myClass (或其他内容)。 Now, add a line to your Makefile underneath the for loop above that says echo "typedef "$MY_TYPE" myClass;" >>all_headers.h 现在,在上面的for循环下面的Makefile中添加一行代表echo "typedef "$MY_TYPE" myClass;" >>all_headers.h echo "typedef "$MY_TYPE" myClass;" >>all_headers.h . echo "typedef "$MY_TYPE" myClass;" >>all_headers.h When you build your program, invoke 'make' with something like make MY_TYPE=E0614 and your typedef will be automatically filled in with the class you are wanting to test. 在构建程序时,使用make MY_TYPE=E0614调用'make',你的typedef将自动填入你想要测试的类。

If you're on Unix system, you can have a softlink that points to the latest excercise. 如果您使用的是Unix系统,则可以使用指向最新练习的软链接。

ln -s e0615.h latest.h ln -s e0615.h latest.h

and name your class E instead of E0614, of course 当然,并命名你的E级而不是E0614

PS To the best of my knowledge, you can't do #include xxx* PS据我所知,你不能做#include xxx*

Don't use one main.cpp which you modify for each exercise. 不要使用为每个练习修改的一个main.cpp。 This solution makes use of make's builtin rules, so you only have to type make e0614 and it will generate e0614.cpp, compile, and link it. 此解决方案使用make的内置规则,因此您只需键入make e0614 ,它将生成e0614.cpp,编译并链接它。 You can customize each .cpp file (they won't be regenerated as written below) and maintain all of that history to refer to as you complete exercises, rather than erasing it as you move from one to the next. 您可以自定义每个.cpp文件(它们不会按照下面的说明重新生成)并保留所有历史记录,以便在您完成练习时引用,而不是在从一个文件移动到另一个文件时将其删除。 (You should also use source control, such as Mercurial .) (您还应该使用源控件,例如Mercurial 。)

Makefile Makefile文件

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

You can generate boilerplate code with scripts, because you don't want it to be tedious either. 您可以使用脚本生成样板代码,因为您不希望它也很乏味。 There are several options for these scripts—and I use a variety of languages including C++, Python, and shell—but the Python below is short and should be simple and clear enough here. 这些脚本有几种选择 - 我使用各种语言,包括C ++,Python和shell--但下面的Python很简短,应该简单明了。

Sample generate script 示例生成脚本

#!/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()

Make a master include file containing the names of all the headers you want. 创建一个包含所需标题的主包含文件。

It's a really bad idea to include *, even if you could. 包括*是一个非常糟糕的主意,即使你可以。

You could use conditional compilation for the class name by using concatenation. 您可以使用串联对条件名称使用条件编译。

// Somewhere in your other files
define CLASS_NUMBER E0614

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

// in main()
ENTERCLASSNUMBER(CLASS_NUMBER)

Don't know about the includes though. 虽然不知道包括。 As suggested above, a script might be the best option. 如上所述,脚本可能是最佳选择。

writing a makefile rule to pass the name of the executable as a -DHEADERFILE=something parameter to the compiler shouldn't be difficult at all. 编写一个makefile规则来将可执行文件的名称作为-DHEADERFILE = something参数传递给编译器应该不难。 Something like: 就像是:

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

OTOH, I don't know if #include does macro expansion on the filename. OTOH,我不知道#include是否对文件名进行宏扩展。

sed -i 's/\<\\([eE]\\)[0-9]+\\>/\19999/' main.cpp

Replace 9999 with the required number. 将9999替换为所需的数字。 There might be better ways. 可能有更好的方法。

Why not using object mechanisms ? 为什么不使用对象机制?

You can use an Exemplar strategy for this. 您可以使用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);
  }
};

Okay, that's the base. 好的,这是基础。

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

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

// Exercise007.cpp
Exercise007 gExemplar007;

And for 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;
}

And here, you don't need any script ;) 在这里,你不需要任何脚本;)

try this:- 试试这个:-

#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

later include this in ur main program that is cpp file 稍后在你的主程序中包含这个是cpp文件

#include "a.h"

...your program ......你的程序

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM