Makro funktioniert nicht



  • Hi, ich erweitere meine Klassen um Typinformationen und stelle dazu drei Makros bereit, um sich die Tipparbeit zu sparen. Jeweils ein Makro für normale Klassen, eines für Klassen mit einem Templateparameter und ein weiteres für Klassen mit zwei Templateparametern. Das klappt auch soweit. Allerdings hat letzteres Makro in einem bestimmten Fall scheinbar Probleme. Leider komme ich nicht auf den Fehler.
    Das interessante ist, dass die Funktion ohne Makro geschrieben (siehe unten auskommentiert) funktioniert, aber mit Makro nicht.
    Ich hoffe ihr könnt mir weiterhelfen. Siehe folgendes minimal Programm:

    #include <iostream>
    #include <string.h>
    
    class Base
    {
    public:
    	Base() {}
    	virtual ~Base() {};
    
    	static int Id();
    };
    
    int Base::Id()
    {
    	std::cout << "Function Base::Id() was called." << std::endl;
    	return 0;
    }
    
    //--------------------------------------------------------------------------------
    
    template <class TKey, class TValue>
    class TestPair : public Base
    {
    public:
    	TestPair() {};
    };
    
    //--------------------------------------------------------------------------------
    
    template <class T>
    class ITestInterface : public virtual Base
    {
    public:
    	static int Id();
    };
    
    template <class T>
    int ITestInterface<T>::Id()
    {
    	std::cout << "Function ITestInterface<T>::Id() was called." << std::endl;
    	return 42;
    }
    
    //--------------------------------------------------------------------------------
    
    template <class TKey, class TValue>
    class TestClass : public ITestInterface< TestPair<TKey, TValue> >
    {
    public:
    	TestClass() {};
    
    	static int Id();
    };
    
    //--------------------------------------------------------------------------------
    
    #define TEST_MACRO(NAME, BASECLASS) \
    	template <class TKey, class TValue> \
    	int NAME<TKey, TValue>::Id() \
    	{ \
    		static int id(BASECLASS::Id()); \
    		return id; \
    	}
    
    //Das funktioniert NICHT:
    
    TEST_MACRO(TestClass, ITestInterface< TestPair<TKey, TValue> >);
    
    //Das funktioniert:
    
    /*template <class TKey, class TValue>
    int TestClass<TKey, TValue>::Id()
    {
    	static int id(ITestInterface<TestPair<TKey, TValue>>::Id()); \
    	return id;
    }*/
    
    //--------------------------------------------------------------------------------
    
    int main()
    {
    	TestClass<std::string, int> test;
    	test.Id();
    	std::cout << "Press any key to continue..." << std::endl;
    	std::cin.get();
    }
    

    Bei Ideone bekomme ich folgende Fehlermeldung:

    prog.cpp:67:63: error: macro "TEST_MACRO" passed 3 arguments, but takes just 2
    TEST_MACRO(TestClass, ITestInterface< TestPair<TKey, TValue> >);
    ^
    prog.cpp:67:1: error: 'TEST_MACRO' does not name a type
    TEST_MACRO(TestClass, ITestInterface< TestPair<TKey, TValue> >);

    Schaut fast nach einem Compilerfehler aus.



  • Woher soll das Makro wissen, dass es das Komma ignorieren soll?



  • MakroDef schrieb:

    Schaut fast nach einem Compilerfehler aus.

    die Meldung kommt vom Preprocessor. Der macht nur Textersetzung.

    TEST_MACRO(TestClass, ITestInterface< TestPair<TKey, TValue> >);
    

    2 kommas -> 3 parameter beim Macroaufruf


  • Mod

    manni66 schrieb:

    Woher soll das Makro wissen, dass es das Komma ignorieren soll?

    Eine modernere Variante des Präprozessors würde Inhalte von Klammern jeglicher Art ( {} , <> ) entsprechend ignorieren.

    Natürlich würde dies Code kaputt machen. E.g. solchen, der Chevrons als Operatoren anwendet. Dort müssten wiederum ( und ) zum Einsatz kommen. I.e. F(a<b, b>c) => F((a<b), (b<c)) .



  • Arcoth schrieb:

    manni66 schrieb:

    Woher soll das Makro wissen, dass es das Komma ignorieren soll?

    Eine modernere Variante des Präprozessors würde Inhalte von Klammern jeglicher Art ( {} , <> ) entsprechend ignorieren

    Ja, hätte wäre wenn - iss aber nich, darum Fehler.


  • Mod

    manni66 schrieb:

    [
    Ja, hätte wäre wenn - iss aber nich, darum Fehler.

    Deine Frage war, woher der Präprozessor die Information holen solle, das Komma zu ignorieren. Das ist eben schnell beantwortet. Dass er es nicht tut, ist etwas anderes. 😛



  • Danke euch, da wäre ich im Leben nicht drauf gekommen.

    Meine erste Idee war nun ein define zu benutzen, um diesen Fehler zu umgehen:

    #define base ITestInterface< TestPair<TKey, TValue>
    TEST_MACRO(TestClass, base);
    

    Da ich mich aber in Header-Dateien befinde möchte ich nur ungerne den globalen Namespace mit defines oder typedefs zumüllen. Evtl. jemand noch eine bessere Idee?



  • Arcoth schrieb:

    manni66 schrieb:

    [
    Ja, hätte wäre wenn - iss aber nich, darum Fehler.

    Deine Frage war, woher der Präprozessor die Information holen solle, das Komma zu ignorieren. Das ist eben schnell beantwortet. Dass er es nicht tut, ist etwas anderes. 😛

    Du versuchst mal wieder, dummes Zeug zu rechtfertigen. Lass es lieber ...



  • manni66 schrieb:

    Woher soll das Makro wissen, dass es das Komma ignorieren soll?

    Das ist so eine von den Antworten in dem Stil, wie er mir bei dir überdurchschnittlich häufig auffällt.
    Hilfreicher, als zu fragen, warum man sich denn so dämlich anstellt, wäre vielleicht eine kurze Erklärung, weshalb der Fehler auftritt (siehe Antwort von __cu) und ein Tip wie man das Problem vermeiden kann, z.B. mit:

    #define COMMA() ,
    TEST_MACRO(TestClass, ITestInterface< TestPair<TKey COMMA() TValue> >);
    

    siehe z.B. auch BOOST_PP_COMMA().
    Das ist keine besonders schöne Lösung, aber immer noch besser als die ganzen zusätzlichen Defines.

    Finnegan



  • Finnegan schrieb:

    manni66 schrieb:

    Woher soll das Makro wissen, dass es das Komma ignorieren soll?

    Das ist so eine von den Antworten in dem Stil, wie er mir bei dir überdurchschnittlich häufig auffällt.
    Hilfreicher, als zu fragen, warum man sich denn so dämlich anstellt,

    Du interpretierst da etwas in die Frage hinein, das dort nicht steht. Der Fragesteller glaubt, alles richtig gemacht und einen Compilerfehler gefunden zu haben. Die Frage weist ihn auf das eigentliche Problem hin, nicht mehr und nicht weniger.

    Finnegan schrieb:

    wäre vielleicht eine kurze Erklärung, weshalb der Fehler auftritt

    Das halte ich für kontraproduktiv. Programmieren lernen heißt zu einem sehr großen Teil, Fehler zu machen, sie zu finden und und beheben. Einfach eine fertige Lösung präsentieren ist da wenig hilfreich.


Anmelden zum Antworten