Parameterliste von Funktion in Abhängigkeit vom Template?



  • Hi,

    ich bastel grad mal wieder mit C++ rum und habe folgendes Problem:

    Ich würde gerne eine Erzeugerfunktion (für Komponenten eines Entity-Component-Systems) schreiben, welche in Abhängigkeit von dem übergebenen Templatetyp (oder auf andere Weise) eine unterschiedliche Zahl von Parametern verlangt, die auch vom Typ her verschieden sein dürfen.

    Also z.B. hätte ich gerne das

    dummyCreate<Foo>(1,2,"dummy");
    dummyCreate<Bar>('d');
    

    funktioniert. Natürlich nicht zwingend mit Templates, hatte nur direkt daran denken müssen.
    Oder meint ihr, dass es sinnvoller ist einfach separate Funktionen für Foo und Bar zu schreiben?



  • Was haltet ihr von

    template<typename T, typename V>
    void myGenerator(V v)
    {
     std::cout << std::get<0>(v) << std::endl; //dummy ausgabe
    }
    
    int main()
    {
    myGenerator<Foo>(std::make_tuple(1,2,"test"));
    return 0;
    }
    

    ?


  • Mod

    template <typename T, typename... Args>
    void dummyCreate(Args&&... args) {
        // Tu etwas mit args
    }
    

    Warum die Natur der Argumente direkt eingeschränkt werden sollte, ist unklar. Lieber einfach benutzen wie gewünscht; falsche Argumente führen halt zu einem Fehler bei der Instantiierung.



  • Arcoth schrieb:

    template <typename T, typename... Args>
    void dummyCreate(Args&&... args) {
        // Tu etwas mit args
    }
    

    Warum die Natur der Argumente direkt eingeschränkt werden sollte, ist unklar. Lieber einfach benutzen wie gewünscht; falsche Argumente führen halt zu einem Fehler bei der Instantiierung.

    Ah, daran hatte ich mich nebulös erinnert aber bin nicht mehr drauf gekommen^^ Danke, ich schau mal ob ich deine oder meine Variante benutze 🙂



  • Weitere Frage:

    Nun habe ich testweise folgendes geschrieben:

    template <typename T>
        void addComponent(const Entity& e)
        {
            std::cout << "done\n";
        }
    
        template <typename T, typename V, typename ...Args>
        void addComponent(const Entity& e, const V& v, const Args&... args) {
            unsigned int n = sizeof...(args);
            std::cout << v << std::endl;
            addComponent<T>(e, args...);
        }
    

    was leider nicht funktioniert.
    Streit man jedoch die "unsigned int n = ..." Zeile funktioniert es fehlerlos.
    Was ist hier los?

    Fehlermeldung im oberen Fall ist:

    ||=== Build: Debug in sfml2_2_base (compiler: GNU GCC Compiler) ===|
    D:\Projekte\sfml2_2_base\main.cpp||In instantiation of 'void UnitFactory::addComponent(const Entity&, const V&, const Args& ...) [with T = DummyComponent; V = int; Args = {int, char [5]}; Entity = unsigned int]':|
    D:\Projekte\sfml2_2_base\main.cpp|119|required from here|
    D:\Projekte\sfml2_2_base\main.cpp|131|warning: unused variable 'n' [-Wunused-variable]|
    D:\Projekte\sfml2_2_base\main.cpp||In instantiation of 'void UnitFactory::addComponent(const Entity&, const V&, const Args& ...) [with T = DummyComponent; V = int; Args = {char [5]}; Entity = unsigned int]':|
    D:\Projekte\sfml2_2_base\main.cpp|133|required from 'void UnitFactory::addComponent(const Entity&, const V&, const Args& ...) [with T = DummyComponent; V = int; Args = {int, char [5]}; Entity = unsigned int]'|
    D:\Projekte\sfml2_2_base\main.cpp|119|required from here|
    D:\Projekte\sfml2_2_base\main.cpp|131|warning: unused variable 'n' [-Wunused-variable]|
    D:\Projekte\sfml2_2_base\main.cpp||In instantiation of 'void UnitFactory::addComponent(const Entity&, const V&, const Args& ...) [with T = DummyComponent; V = char [5]; Args = {}; Entity = unsigned int]':|
    D:\Projekte\sfml2_2_base\main.cpp|133| recursively required from 'void UnitFactory::addComponent(const Entity&, const V&, const Args& ...) [with T = DummyComponent; V = int; Args = {char [5]}; Entity = unsigned int]'|
    D:\Projekte\sfml2_2_base\main.cpp|133|required from 'void UnitFactory::addComponent(const Entity&, const V&, const Args& ...) [with T = DummyComponent; V = int; Args = {int, char [5]}; Entity = unsigned int]'|
    D:\Projekte\sfml2_2_base\main.cpp|119|required from here|
    D:\Projekte\sfml2_2_base\main.cpp|131|warning: unused variable 'n' [-Wunused-variable]|
    ||=== Build finished: 1 error(s), 11 warning(s) (0 minute(s), 1 second(s)) ===|



  • Seltsam, Ideone.com kompiliert es ohne Probleme.
    Bug vom GCC?

    Ganzes Programm zum Copy+Paste und runnen (Zeile 103 fängt die Klasse an):

    #include <iostream>
    #include <vector>
    #include <list>
    #include <unordered_map>
    #include <memory>
    #include <tuple>
    
    class BaseComponent;
    
    typedef unsigned int ID;
    typedef ID Entity;
    typedef unsigned int Type;
    
    Type global_type = 0;
    
    enum class ComponentType {DUMMYCOMPONENT=0, DUMMYCOMPONENT1};
    
    typedef std::vector<std::unique_ptr<BaseComponent>> Components;
    typedef std::vector<Entity> Entities;
    
    struct EnumClassHash
    {
        template <typename T>
        std::size_t operator()(T t) const
        {
            return static_cast<std::size_t>(t);
        }
    };
    
    template <typename T>
    Type getType()
    {
        static Type mytype = global_type++;
        return mytype;
    }
    
    std::unordered_map<Entity, Components> id2comp;
    std::unordered_map<ComponentType, Entities, EnumClassHash> comp2id;
    
    class BaseComponent
    {
    private:
        ComponentType m_type;
    
    public:
        BaseComponent(const ComponentType type)
        :m_type(type)
        {}
    
        ComponentType Type() const
        {
            return m_type;
        }
    };
    
    class DummyComponent
    :public BaseComponent
    {
    public:
        DummyComponent()
        :BaseComponent(ComponentType::DUMMYCOMPONENT)
        {
    
        }
    };
    
    class DummyComponent2
    :public BaseComponent
    {
    public:
        DummyComponent2()
        :BaseComponent(ComponentType::DUMMYCOMPONENT1)
        {
    
        }
    };
    
    ID generateId()
    {
        static ID current_id = 0;
        return current_id++;
    }
    
    Entity generateEntity()
    {
        static Entity current_entity = 0;
        return current_entity++;
    }
    
    Entity createEntity()
    {
        Entity e = generateEntity();
        id2comp[e];
        return e;
    }
    
    class UnitFactory
    {
    private:
        template <typename T, typename ...Args>
        T& pass(const T& t, const Args&... args)
        {
            return t;
        }
    
    public:
        UnitFactory(){}
        void buildUnit()
        {
            Entity e = generateEntity();
            addComponent<DummyComponent>(e, 2, 1, "test");
            //addComponent<DummyComponent2>(e, 'c');
        }
    
        template <typename T>
        void addComponent(const Entity& e)
        {
            std::cout << "done\n";
        }
    
        template <typename T, typename V, typename ...Args>
        void addComponent(const Entity& e, const V& v, const Args&... args) {
            std::cout << v << std::endl;
            std::size_t n = sizeof...(args);
            addComponent<T>(e, args...);
        }
    };
    
    class SystemBase
    {
    private:
        ID m_id;
        virtual void onStartUp()=0;
    
    public:
        SystemBase()
        :m_id(generateId())
        {}
    
        ~SystemBase()
        {}
    
        virtual void process()=0;
    };
    
    class SystemTest
    :public SystemBase
    {
    private:
        void onStartUp()
        {
            //std::cout << "Starting up" << std::endl;
        }
    public:
        SystemTest()
        :SystemBase()
        {
            onStartUp();
        }
    
        void process()
        {
            //std::cout << "Processing" << std::endl;
        }
    };
    
    int main()
    {
    
        UnitFactory u;
        u.buildUnit();
    
        //Entity e = createEntity();
    
    //    while (mygame.isRunning())
    //    {
    //        mygame.run();
    //    }
        return 0;
    }
    


  • Sooo, hat sich geklärt. Lag natürlich daran, dass die übergebenen Parameter (1,2, "test") rvalues sind und ich ne Referenz verwendete. Kann zu, hat sich alles geklärt.

    Sorry für den Wust, beim nächsten Mal dann mit Account 😉 ^^


Log in to reply