I'm going through exercises of a C++ book. 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:
#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:
Can I include all headers in the directory so at least I don't have to change the #include line?
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?
Update:
I ended up following Poita_'s advice to generate main.cpp via a script.
Since I'm using an IDE (Visual Studio), I wanted this integrated with it, so did a bit of research on how. 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. So in this instance I used a simple batch file, and it gets passed the name of the currently selected file in 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. Substitute X with the number corresponding to the tool you created. 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. You can then assign an icon to the shortcut (it's the BuildMain command shown below):
No. You have to include them all if that's what you want to do.
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...
If you build your code using make, you should be able to do this.
Can I include all headers in the directory so at least I don't have to change the #include line?
Change your include line to something like #include <all_headers.h>. Now, you can let your Makefile auto-generate all_headers.h with a target like:
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'.
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?
You can do this if you abstract away your class with a typedef. In your example, change your class name from E0614 to myClass (or something). Now, add a line to your Makefile underneath the for loop above that says 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.
If you're on Unix system, you can have a softlink that points to the latest excercise.
ln -s e0615.h latest.h
and name your class E instead of E0614, of course
P.S. To the best of my knowledge, you can't do #include xxx*
Don't use one main.cpp which you modify for each exercise. 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. 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. (You should also use source control, such as Mercurial.)
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.
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. 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.
sed -i 's/\<\\([eE]\\)[0-9]+\\>/\19999/' main.cpp
Replace 9999 with the required number. There might be better ways.
Why not using object mechanisms ?
You can use an Exemplar strategy for this.
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
#include "a.h"
...your program
Related
I recently adopted a style where I try to avoid unnecesary classes / scopes, so the code cannot be splitted in files by classes or functions, since almost everything happens in main. Of course for a lot of lines of code, this will be pretty hard to read, so I must split it somehow. I would like to do something like this:
#include <iostream>
int main()
{
#include "test.cpp"
return 0;
}
// test.cpp
std::cout << "Test";
Is there a way to tell the compiler to copy it exactly like that? And if yes, can I also make use of the IntelliSense (VS 2017)?
Regardless of the design is a good or a bad idea, you can check what the "final" output file looks like. If you are using GCC, you can use -E flag, e.g.
g++ -E main.cpp > out
This command executes the preprocessor and write the output to the out file.
In this example, my out file looks like
// bunch of STL codes due to <iostream>
// ...
# 2 "main.cpp"
int main()
{
# 1 "test.cpp" 1
std::cout << "Test";
# 5 "main.cpp" 2
return 0;
}
I'm trying to get the benefits of splitting without two files. Split compilation without splitting storage.
I understand the benefits of separating .h and .cpp files, but I really dislike having the files be separate, specifically when the classes are tiny and each file could fit on the same page.
Is there a precompiler option, or perhaps any other trick which would allow me to keep the benefits of separation, while having the text all in the same place? For example:
EDIT: please do not focus too much on this example. It was meant to show off an imaginary pre-processor arg #CPP_SPLIT. The actual code is unimportant, please, please ignore it.
// TinyClass.h
class TinyClass {
TinyClass();
int answerToLife();
}
// the following is a fake compiler arg
// in this example it would be totally unnecessary,
// but many of my classes have some form of circular referencing
// and can not include all the code in the .h file
#CPP_SPLIT
TinyClass::TinyClass() {}
TinyClass::answerToLife() { return 42; }
#CPP_SPLIT_END
I'm not sure it's worth the effort, but you could place the contents of your .cpp file into #ifdef'd sections, like this:
#ifdef PART_ONE
[...]
#endif
#ifdef PART_TWO
[...]
#endif
#ifdef PART_THREE
[...]
#endif
... and then recompile the file over multiple passes, like this:
g++ -DPART_ONE -opart1.o myfile.cpp
g++ -DPART_TWO -opart2.o myfile.cpp
g++ -DPART_THREE -opart3.o myfile.cpp
g++ -o a.out part1.o part2.o part3.o
You can simply put the implementation directly in the header like this:
// TinyClass.h
class TinyClass {
TinyClass() {}
int answerToLife() { return 42; }
};
Also inline might help to do what you want:
// TinyClass.h
class TinyClass {
TinyClass();
int answerToLife();
}
inline TinyClass::TinyClass() {}
inline int TinyClass::answerToLife() { return 42; }
Another potential solution to this appears to be the proposed c++ modules standard. If you happen across this many years down the line, look there.
I have two files, client.vala and lib.vapi.
The VAPI defines a class (that would usually talk to C code):
class Toplevel.Sub.CClass
{
public uint i;
}
And client.vala uses the class:
class Toplevel.Sub.UserClass
{
public Toplevel.Sub.CClass c_class;
}
int main()
{
var cls = new Toplevel.Sub.UserClass();
cls.c_class.i = 0;
return 0;
}
When I attempt to compile the program, I get an error:
$ valac client.vala lib.vapi
/tmp/bug/client.vala.c:7:20: fatal error: client.h: No such file or directory
compilation terminated.
error: cc exited with status 256
Compilation failed: 1 error(s), 0 warning(s)
The compiler seems to want a header generated for the functions in client.vala.
Is this a bug or am I missing something?
You've discovered something I didn't know about the Vala compiler. client.h is the default C header name generated by the compiler when no alternative is provided. It has used the basename of the source Vala file. You can change this using the cheader_filename CCode detail. Change what you have in your VAPI to:
[CCode (cheader_filename = "my_real_c_header.h")]
class Toplevel.Sub.CClass
{
public uint i;
}
and you will see the include is now #include "my_real_c_header.h"
By the way if you compile with valac client.vala --vapididr . --pkg lib you will see the header is included as #include <my_real_c_header.h>. Personally I think VAPIs should be used with the --pkg option.
If you are literally using Toplevel.Sub.CClass to 'usually talk to C code' then you have misunderstood the purpose of a VAPI. I take 'talk to' to mean calling various C functions and collecting the results so they can be presented in a more Vala friendly way to the rest of your program. So it is a wrapper interface.
A VAPI contains instructions to the Vala compiler to translate names into the right names for the C interface. For example you might have a very simple C function, void top_level_do_something (), that you want to use in Vala. In Vala it helps to use a namespace so the VAPI could be:
[CCode (cheader_filename = "my_real_c_header.h")]
namespace TopLevel {
[CCode (cname = "top_level_do_something")]
public void do_something ();
}
You can then call this in Vala with TopLevel.do_something () and the compiler would write this out as top_level_do_something () in C.
Take a look at Writing a VAPI Manually for more details.
Im currently playing around with pybind11 a bit. Im trying to create a C++ class which then gets passed to a python interpreter embedded in my C++ source.
I created some dummy class just to test the basic functionality I kept everything in a single source file. This approach compiled and ran without any problems.
Now I separated my dummy Class Test into a Test.h and Test.cpp
Test.h
#pragma once
#include<iostream>
#include"pybind11\pybind11.h"
namespace py = pybind11;
class Test
{
public:
Test(const std::string &s);
~Test();
void printStr();
private:
std::string _s;
};
Test.cpp
#include "Test.h"
PYBIND11_MODULE(TestModule, m)
{
py::class_<Test>(m, "Test")
.def(py::init<const std::string &>())
.def("printStr", &Test::printStr);
}
Test::Test(const std::string &s) : _s(s)
{
}
Test::~Test()
{
}
void Test::printStr()
{
std::cout << "---> " << _s << std::endl;
}
main.cpp
#include"Test.h"
int main(int argc, char **argv)
{
PyImport_AppendInittab("TestModule", PyInit_TestModule);
Py_Initialize();
PyRun_SimpleString("import TestModule");
PyRun_SimpleString("t = TestModule.Test(\"str\")");
PyRun_SimpleString("t.printStr()");
Py_Finalize();
getchar();
return 1;
}
After putting the Class Test into a new file the Compiler cannot find the PyInit_TestModule (main.cpp line: 6) anymore since this is generated by the PYBIND11_MODULE Macro which lives in the Test.cpp file(MSVS2017 Error: C2065).
I tried putting the PYBIND11_MODULE Macro into the Test.h. This however resulted in a linker error which said that "_PyInit_TestModule" is already defined in main.obj (MSVS2017 Error: LNK2005)
Putting the PYBIND11_MODULE Macro in the main.cpp file works.
However I feel like this will become quite unreadable as soon as you put a lot of custom Module definitions into main.cpp or even worse you have multiple Python-Interpreter being started from different source files where you then
need to put the same definition in all those files which will be a mess and most likely turn into a linker error.
Has one of you faced the same Problem and how did you solve it?
I created a file of his own for the bindings, and compiled/linked it together with the original c++ file. This way:
1) Test.h + Test.cpp contain only c++ code of your class
2) Test-bindings.cpp contains the PYBIND11_MODULE and #include <Test.h>
3) Building (with cmake). You will get a PyTest.so file out of it, that you can load in python.
# c++ libray
add_library(TestLib SHARED /path/to/Test.h /path/to/Test.cpp)
# bindings
add_subdirectory(pybind11) # you must have downloaded this repo
include_directories(/path-only/to/Test.h)
pybind11_add_module(PyTest SHARED /path/to/Test-bindings.cpp /path/to/Test.cpp)
4) (I suggest you to) write the main in python, using the python-binding you just created
5) In your main.py
import PyTest
# do something
Overview
I am trying to develop a C++ application which allows for user-created plugins.
I found a nice library called Pluma (http://pluma-framework.sourceforge.net/) which functionally seems to be exactly what I want.
After going through their tutorial, I was able to (with a bit of difficulty) convince the plugin to compile. However, it refuses to play nice and connect with the main program; returning various errors depending on how I try to implement them.
Problem
If I comment out the line labeled 'Main problem line' (in the last file, main.cpp), the plugin compiles successfully, and the main app can recognize it, but it says that "Nothing registered by plugin 'libRNCypher'", and none of the functions can be called.
If I compile that line, the main application instead says "Failed to load library 'Plugins/libRNCypher.so'. OS returned error: 'Plugins/libRNCypher.so: undefined symbol: _ZTIN5pluma8ProviderE".
My guess is that it has something to do with the way the plugin was compiled, as compiling it initially did not work and Code::Blocks told me to compile with "-fPIC" as a flag (doing so made it compile).
Code
Code below:
Main.cpp
#include "Pluma/Pluma.hpp"
#include "CryptoBase.h"
int main()
{
pluma::Pluma manager;
manager.acceptProviderType< CryptoBaseProvider >();
manager.loadFromFolder("Plugins", true);
std::vector<CryptoBaseProvider*> providers;
manager.getProviders(providers);
return 0;
}
CryptoBase.h
#ifndef CRYPTOBASE_H_INCLUDED
#define CRYPTOBASE_H_INCLUDED
#include "Pluma/Pluma.hpp"
#include <string>
#include <vector>
#include <bitset>
//Base class from which all crypto plug-ins will derive
class CryptoBase
{
public:
CryptoBase();
~CryptoBase();
virtual std::string GetCypherName() const = 0;
virtual std::vector<std::string> GetCryptoRecApps() const = 0;
virtual void HandleData(std::vector< std::bitset<8> > _data) const = 0;
};
PLUMA_PROVIDER_HEADER(CryptoBase)
#endif // CRYPTOBASE_H_INCLUDED
RNCypher.h (This is part of the plugin)
#ifndef RNCYPHER_H_INCLUDED
#define RNCYPHER_H_INCLUDED
#include <string>
#include <vector>
#include <bitset>
#include "../Encoder/Pluma/Pluma.hpp"
#include "../Encoder/CryptoBase.h"
class RNCypher : public CryptoBase
{
public:
std::string GetCypherName() const
{
return "RNCypher";
}
std::vector<std::string> GetCryptoRecApps() const
{
std::vector<std::string> vec;
vec.push_back("Storage");
return vec;
}
void HandleData(std::vector< std::bitset<8> > _data) const
{
char letter = 'v';
_data.clear();
_data.push_back(std::bitset<8>(letter));
return;
}
};
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase);
#endif // RNCYPHER_H_INCLUDED
main.cpp (This is part of the plugin)
#include "../Encoder/Pluma/Connector.hpp"
#include "RNCypher.h"
PLUMA_CONNECTOR
bool connect(pluma::Host& host)
{
host.add( new RNCypherProvider() ); //<- Main problem line
return true;
}
Additional Details
I'm compiling on Ubuntu 16.04, using Code::Blocks 16.01.
The second error message seems to not come from Pluma itself, but a file I also had to link, #include <dlfcn.h> (which might be a Linux file?).
I would prefer to use an existing library rather than write my own code as I would like this to be cross-platform. I am, however, open to any suggestions.
Sorry for all of the code, but I believe this is enough to reproduce the error that I am having.
Thank You
Thank you for taking the time to read this, and thank you in advance for your help!
All the best, and happy holidays!
I was not able to reproduce your problem, however looking at
http://pluma-framework.sourceforge.net/documentation/index.htm,
I've noticed that:
in your RNCypher.h file you miss something like
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase)
it seems also that there's no file CryptoBase.cpp containing something like
#include "CryptoBase.h"
PLUMA_PROVIDER_SOURCE(CryptoBase, 1, 1);
finally, in CryptoBase.h I would declare a virtual destructor (see Why should I declare a virtual destructor for an abstract class in C++?) and provide a definition to it, while you should not declare a default constructor without providing a definition to it (see for instance Is it correct to use declaration only for empty private constructors in C++?); of course the last consideration is valid unless there's another file in which you have provided such definitions.