Template type an Macro übergeben



  • Hallo

    Ist es möglich einen typ an ein Makro zu übergeben und diesen dann als template Parameter zu nutzen

    also so in der Art:

    class xyz
    {
         template<T>
         xyz()
         {
             _y = make_shared<T>();
         }
    }
    
    #define MyMakro(myType) xyz<myType>();
    

  • Mod

    Makros sind reine Textersetzungen, die sich überhaupt nicht um die Bedeutung des ersetzten Textes kümmern. Also ja.

    Es kommt aber die Gegenfrage auf, wieso jemand, der Templates kennt, freiwillig die enorm vielen und großen Nachteile von Makros in Kauf nehmen möchte, wenn doch Templates quasi die gefixte Version von Makros sind.



  • "Makros sind reine Textersetzungen, die sich überhaupt nicht um die Bedeutung des ersetzten Textes kümmern. Also ja. "

    Geht aber nicht!

    Das Makro benötige ich wegen etwas anderem

    Hier das konkrette Makro:

    #define THROW_TRACEABLE_EXCEPTION_INNER(message, innerexception, exeptiontype) throw autobase::TraceableException<exeptiontype>(message, PROJECT_NAME,__FILE__, __LINE__, __FUNCTION__, innerexception);
    

    um nun in meiner klasse TraceableException die Inner Exception per shared_ptr zu erzeugen benötige ich den konkretten Typ.

    Aufruf:

    catch(TraceableException &inner)
    {
       THROW_TRACEABLE_EXCEPTION_INNER("outer", inner, TraceableException);
    }
    

    Fehlermeldung: egal welchen exceptiontyp ich angebe ich erhalte die Meldung
    'TraceableException' does not name a value


  • Mod

    Reine Textersetzung!

    Dies kommt raus:

    throw autobase::TraceableException<TraceableException>("outer", PROJECT_NAME,__FILE__, __LINE__, __FUNCTION__, inner);
    

    (Plus natürlich noch Ersetzung der vordefinierten Makros)

    Sieht das wie gültiges C++ aus? Möglich, weil C++ viel erlaubt, aber sehr unwahrscheinlich. TraceableException wird wohl kaum gleichzeitig ein Typ als auch ein Wert sein.



  • Problem ist wohl das der Konstruktor keinen Template Type haben darf.



  • Func()() schrieb:

    Problem ist wohl das der Konstruktor keinen Template Type haben darf.

    Template-Ctor geht schon. Nur kannst du die Template-Arguments dabei dann nicht explizit angeben. Du kannst dir aber mit z.B. boost::type<T> behelfen.

    Also

    `throw autobase::TraceableException<InnerType>("outer", PROJECT_NAME,FILE, LINE, FUNCTION, inner);

    =>

    throw autobase::TraceableException(boost::type<InnerType>(), "outer", PROJECT_NAME,FILE, LINE, FUNCTION, inner);

    `

    Oder den Typ gleich automatisch bestimmen lassen - sehe keinen Grund warum das nicht gehen sollte.
    `

    =>

    throw autobase::TraceableException("outer", PROJECT_NAME,FILE, LINE, FUNCTION, inner);

    `

    Oder natürlich über eine Hilfsfunktion:
    `

    =>

    autobase::TraceableException::throw_<InnerType>("outer", PROJECT_NAME,FILE, LINE, FUNCTION, inner);

    `



  • Hallo hustbear:

    1: boost ungerne 🙂
    3: Hilfsfunktion so habe ich es momentan gemacht nur nicht den throw in der Hilfsfunktion. sondern
    throw autobase::TraceableException::Create<InnerType>("outer", PROJECT_NAME,__FILE__, __LINE__, __FUNCTION__, inner);

    sonst bekomme ich an den enstprechenden Aufrufen eine Fehlermeldung wenn ich keinen Rückgabewert definiere wenn dies die Funktion erfordert

    Also

    int method()
    {
        ....
        THROW_TRACEABLE_EXCEPTION_INNER()
    }
    

    2: wie meinst du das automatisch bestimmen lassen. Wie mache ich das?

    make_shared<??> (inner)
    


  • ad 1: boost::type ist ein Einzeiler

    template <class T> class type {};
    

    ad 2:
    So mein ich das:

    #include <string>
    #include <memory>
    
    class Foo {
    public:
        template <class T>
        Foo(T const& stuff)
        {
            m_stuff = std::make_shared<T>(stuff); // <- hier NICHT weglassen (geht nicht, da der typ bei make_shared nicht "deduced" werden kann)
        }
    private:
        std::shared_ptr<void> m_stuff;
    };
    
    void Bar()
    {
        std::string stuff;
        Foo f(stuff); // <- hier weglassen
        // bzw.
        throw Foo(stuff); // <- hier weglassen
    }
    

    ad 3: da hilft z.B. BOOST_NORETURN
    Etwas mehr als eine Zeile, aber immer noch sehr übersichtlich:

    #if !defined(BOOST_NORETURN)
    #  if defined(_MSC_VER)
    #    define BOOST_NORETURN __declspec(noreturn)
    #  elif defined(__GNUC__)
    #    define BOOST_NORETURN __attribute__ ((__noreturn__))
    #  elif defined(__has_attribute) && defined(__SUNPRO_CC)
    #    if __has_attribute(noreturn)
    #      define BOOST_NORETURN [[noreturn]]
    #    endif
    #  elif defined(__has_cpp_attribute) 
    #    if __has_cpp_attribute(noreturn)
    #      define BOOST_NORETURN [[noreturn]]
    #    endif
    #  endif
    #endif
    

    Natürlich solltest du das Makro anders nennen falls du es selbst definierst. Damit geht dann:

    BOOST_NORETURN void ThrowSomething();
    
    int Fun(int param) {
    	if (param < 0)
    		ThrowSomething();
    	else
    		return param * param;
    }
    


  • ad 2: Ah ok. Geht das schon immer oder erst ab c++ 11?
    ad 3: gut, dann weiß ich das auch. Aber direkt ein throw im Makro tut es ja auch.

    Zusatzfrage: kann ich den Templatetyp auch auf die basisklasse exception einschränken?



  • Func()() schrieb:

    ad 2: Ah ok. Geht das schon immer oder erst ab c++ 11?

    Das geht schon immer.

    Func()() schrieb:

    Zusatzfrage: kann ich den Templatetyp auch auf die basisklasse exception einschränken?

    Klar.

    class Foo {
    public:
        template <class T>
        Foo(T const& stuff)
        {
            std::exception const* test = &stuff; // <- Compiler Fehler hier wenn T nicht von std::exception abgeleitet ist
            ((void)test); // damit der compiler keine "unused local variable" warning bringt
    
            m_stuff = std::make_shared<T>(stuff);
        }
    private:
        std::shared_ptr<void> m_stuff;
    };
    

    Geht natürlich auch anders, z.B. über std::is_base_of (C++11):

    class Foo {
    public:
        template <class T>
        Foo(T const& stuff)
        {
            static_assert(std::is_base_of<std::exception, T>::value, "T must be derived from std::exception");
    ...
    


  • vielen Dank!


Anmelden zum Antworten