Macros
-
Ist halt unnötigerweise länger, mehr Arbeit und de facto unübersichtlicher.
Klar kann man das jedesmal so hinschreiben.
Man kann auch statt eine Funktion zu schreiben und als inline zu deklarieren jedesmal den code selbst einfügen.
Ich kann auch jedes template manuel zusammenbaun, brauch ich die template möglichkeit von c++ gar nicht mehr.
Das geht schon, nur Sinn machts keinen.
-
Muss ich Janjan Recht geben. Markos sollten in C++ für so etwas nicht genutzt werden... Das war mal C

-
abgesehen vom genannten, wobei das von Kleiner Troll auch ohne makro geht,
manchmal braucht man automatisch generierte unterschiedliche bezeichner, da nimmt man manchmal __count__ oder __line__ und makros.
manchmal braucht man bezeichner und den bezeichner als string, zum beispiel für factories.
oder auch zum testen
#include <iostream> using namespace std; #define SHOW(name) cout<<#name<<" = "<<(name)<<'\n'; int main(){ int x=5; int y=7/x; double z=y*x; SHOW(x); SHOW(y); SHOW(x==y); }Ausgabe
x = 5 y = 1 x==y = 0und natürlich für assert und konsorten.
-
Danke für eure Antworten

Jetz verstehe ich wenigstens Sinn und Zweck dieser Makros.
-
volkard schrieb:
abgesehen vom genannten, wobei das von Kleiner Troll auch ohne makro geht
Hm? Meinst du einfach austippen? Ja, geht. Oder hast du eine andere Lösung im Kopf?
-
Kleiner Troll schrieb:
volkard schrieb:
abgesehen vom genannten, wobei das von Kleiner Troll auch ohne makro geht
Hm? Meinst du einfach austippen? Ja, geht. Oder hast du eine andere Lösung im Kopf?
Was spricht gegen:
template<typename Function, typename T> void Register(Function function, T const& name) { Register_helper(function, SomeTemplate::MyTemplate<Function>, name); }wobei mir hier der Sinn komplett unklar ist.
oder meintest du statt
#define REGISTER_MAKRO(function, name) \ Register(function, SomeTemplate::MyTemplate<function>, name)doch
#define REGISTER_MAKRO(function, name) \ Register(#function, SomeTemplate::MyTemplate<function>(), name)??
-
Kleiner Troll schrieb:
volkard schrieb:
abgesehen vom genannten, wobei das von Kleiner Troll auch ohne makro geht
Hm? Meinst du einfach austippen? Ja, geht. Oder hast du eine andere Lösung im Kopf?
Du hast nicht klargemacht, was
Register(function,SomeTemplate::MyTemplate<function>,name);tun soll.
Aber so frißt es mein Compiler nicht, fürchte ich. Der zweite Parameter scheint nur ein Typ zu sein.
-
Manchmal können Macros einen einfach Tipparbeit abnehmen. Das DRY-Prinzip kann bis zu einem gewissen Grad auch hier agewendet werden. Kleines Beispiel, das ich benutze um einen enum-Wert auf einen Typen zu mappem:
template <CommandID ID> struct CommandID2Type { typedef EmptyType type; }; #define MAPCOMMANDID(id, mappedtype) \ \ template <> \ struct CommandID2Type<id> \ { \ typedef mappedtype type; \ } MAPCOMMANDID(ERROR, std::string); MAPCOMMANDID(OUTPUT, std::string); MAPCOMMANDID(PLAYER_INFO_OPEN, std::vector<OpenPlayerInfo>); MAPCOMMANDID(TABLE_INFO, TableInfo); MAPCOMMANDID(TURN_INFO, TurnInfo); MAPCOMMANDID(PLAY_CARD, CardID); MAPCOMMANDID(SETUP_PLAYERS, std::vector<std::string>); #undef MAPCOMMANDIDjedesmal das stuct komplett auszuschreiben wäre doch ein wenig länglich, so sieht man sofort was passiert, und die Wirkunsweise ist dank #undef begrenzt.
-
Das ganze ist ein bisschen Ansichtssache - man kann mit Makros viel Schindluder treiben, aber das gilt für so ziemlich alles.
Mein Standpunkt ist, dass man Makros mit Vorsicht behandeln sollte, weil es sehr leicht ist, damit zu verschleiern, was eigentlich passiert, wodurch der Code sehr unübersichtlich werden kann, es allerdings Zusammenhänge gibt, in denen Makros schlimmeres verhindern - beispielsweise, den selben Kram zwanzigtausendmal zu schreiben, etwa, wenn dieser sich nicht in eine Funktion auslagern lässt. Das muss dann im Einzelfall entschieden werden.
Konkretes Beispiel: Man schreibt ein C-API um eine C++-Kernbibliothek. Das C-API kennt keine Exceptions, also müssen die vorher abgefangen werden, und häufig in einem solchen Fall auf die gleiche Art und Weise. Da catch-Blöcke sich nicht in Funktionen auslagern lassen, besteht die Wahl bei einem ausreichend großen API dazwischen, die selben zehn oder so Zeilen in jeder Funktion wieder zu copy&pasten oder ein Makro zu schreiben - in so einem Zusammenhang ist ein Makro meines Erachtens nach durchaus vertretbar. Ich berufe mich hier auf das DRY-Prinzip.
Ansonsten gibt es gelegentlich zwischen verschiedenen Compilern Unterschiede in der...ich nenne es mal Auslegung von Standards, für die von Janjan genannten Feature-Makros nicht ausreichen (bzw. bei denen die Umsetzung mit nur diesen Feature-Makros eher unschön ist). Etwa benutze ich für TR1-Header folgendes Konstrukt:
#ifdef __GNUC__ # define TR1_HEADER(header) <tr1/header> #else # define TR1_HEADER(header) <header> #endif #include TR1_HEADER(memory) #include TR1_HEADER(functional) // ... #undef TR1_HEADERAnsonsten kann ich volkard nur zustimmen. Grundlegend ist das relevante Entscheidungskriterium Übersichtlichkeit. Wenn ich zwei Möglichkeiten zur Auswahl habe, von denen eine übersichtlich und eine unübersichtlich ist, nehme ich die unübersichtliche, völlig egal, welche Sprachmittel ich dazu benutzen muss.
-
function ist ein Funktionszeiger mit einer gewissen signatur a, name ist ein std::string, das template hat eine signatur b != a (der einzige Zweck des templates ist genaugenommen die Signatur zu ändern)
Register nimmt nimmt einen Funktionszeiger mit Signatur a, einen mit b, und einen Namen, unter dem es die Funktion unter diesem Namen als callback an 2 voneinander unabhängigen Stellen registriert.Zu Shade of Mine:
function, SomeTemplate::MyTemplate<Function>, name
und
function, SomeTemplate::MyTemplate<function>, name
Ist nicht dasselbe

-
#include <cstdio> #include <cstring> #include <string> void oldFunc(const char *str, int len) { printf("%s, len %i\n", str, len); } #define SHORTER_C_FUNC(x) oldFunc(x, strlen(x)) inline void betterCppFunc(const std::string& str) { SHORTER_C_FUNC(str.c_str()); } inline void betterCppFunc(const char *str) { SHORTER_C_FUNC(str); } int main() { std::string test1 = "bla"; char test2[] = "test"; betterCppFunc(test1); betterCppFunc(test2); }
-
seldon schrieb:
Ansonsten kann ich volkard nur zustimmen. Grundlegend ist das relevante Entscheidungskriterium Übersichtlichkeit. Wenn ich zwei Möglichkeiten zur Auswahl habe, von denen eine übersichtlich und eine unübersichtlich ist, nehme ich die unübersichtliche, völlig egal, welche Sprachmittel ich dazu benutzen muss.
Das ehrt Dich. Aber ich bin um ehrlich zu sein, nicht so fleißig und nehme gelegentlich einfach die übersichtlichere.
-
Äh...Tipfeeler.

-
Kleiner Troll schrieb:
function ist ein Funktionszeiger mit einer gewissen signatur a, name ist ein std::string, das template hat eine signatur b != a (der einzige Zweck des templates ist genaugenommen die Signatur zu ändern)
Register nimmt nimmt einen Funktionszeiger mit Signatur a, einen mit b, und einen Namen, unter dem es die Funktion unter diesem Namen als callback an 2 voneinander unabhängigen Stellen registriert.Soll Register auch ein Makro sein? Falls ja, war Dein Posting ein schwaches Argument.
Fall nein, zeige eine einfache Beispielimplementierung für Register.
So glaube ich noch nicht, daß die Anforderung möglich war.
-
int Singleton::Register(SignaturEins function, SignaturZwei cFunction, const string& name) { if (Register(function, name) != -1) { Register(cFunction, name); return 0; } else { return -1; } }Im echten Beispiel sind "SignaturEins/Zwei" einfach typedefs für einen Funktionszeiger.
Ich hoffe du hast nichts dagegen das ich die Namen etwas generalisiert habe.
-
Das template könnte als Beispiel so aussehen:
template<SignaturEins T> int MyTemplate(int Zahl)
{
std::vector<int> tmp;
tmp.push_back(Zahl);
return T(tmp);
}
-
Compilieren sollte das Programm schon.
-
Ach, du willst ein kompilierbares minimalbeispiel? Sag das doch gleich :>
Warte 10 min, ich stells zusammen.
-
#include <vector> #include <string> #define REGISTER_MAKRO(function, name) \ Register(function, MyTemplate<function>, name) using namespace std; typedef int (*SigEins)(vector<int>); typedef int (*SigZwei)(int); template<SigEins T> int MyTemplate(int Zahl) { vector<int> tmp; tmp.push_back(Zahl); return T(tmp); } int Register(SigEins func, const string& name) { //hier gehts weiter zum registrieren in die eine Richtung, wies genau geht sollte irrelevant sein return 0; //wir gehen davon aus das das registrieren hier erfolgreich war //return -1; //das wird zurückgegeben falls es nicht erfolgreich war } int Register(SigZwei func, const string& name) { //hier gehts weiter zum registrieren in die andere Richtung, wies genau geht sollte irrelevant sein return 0; } int Register(SigEins function, SigZwei cFunction, const string& name) { if (Register(function, name) != -1) { Register(cFunction, name); return 0; } else { return -1; } } int Test(vector<int>) { return 2; } int main() { REGISTER_MAKRO(&Test, "test"); }
-
Noch gehts.
#include <vector> #include <string> using namespace std; typedef int (*SigEins)(vector<int>); typedef int (*SigZwei)(int); template<SigEins T> int MyTemplate(int Zahl) { vector<int> tmp; tmp.push_back(Zahl); return T(tmp); } int Register(SigEins func, const string& name) { //hier gehts weiter zum registrieren in die eine Richtung, wies genau geht sollte irrelevant sein return 0; //wir gehen davon aus das das registrieren hier erfolgreich war //return -1; //das wird zurückgegeben falls es nicht erfolgreich war } int Register(SigZwei func, const string& name) { //hier gehts weiter zum registrieren in die andere Richtung, wies genau geht sollte irrelevant sein return 0; } int Register(SigEins function, SigZwei cFunction, const string& name) { if (Register(function, name) != -1) { Register(cFunction, name); return 0; } else { return -1; } } int Test(vector<int>) { return 2; } #define REGISTER_MAKRO(function, name) \ Register(function, MyTemplate<function>, name) //alles oberhalb unveränder, außer das makro runtergezogen zum besser //anschauen können, während ich das template zusammenfrickle. template<SigEins FUNC> void REGISTER_TEMPLATE(const string& name){ Register(FUNC,MyTemplate<FUNC>,name); } int main() { REGISTER_MAKRO(&Test, "test"); REGISTER_TEMPLATE<&Test>("test"); }Wenn die function auch andere Signaturen als SigEins haben können soll, wird der Aufruf in der main aber schon häßlicher. Da mache ich mich dann aber auch locker und denke an Makros.
Aber spaßig wird's mit
#define REGISTER_MAKRO2(function) \ Register(function, MyTemplate<function>, #function) int main() { REGISTER_MAKRO(&Test, "test"); REGISTER_TEMPLATE<&Test>("test"); REGISTER_MAKRO2(Test); }