Container für beliebige Typen



  • Ich frage mich, ob es möglich ist, in C++ einen Container zu implementieren, der Objekte beliebigen Typens halten könnte. Natürlich macht so ein Container im Konzept von C++ wenig bis keinen Sinn, allerdings finde ich die Frage ganz interessant.
    Erst hatte ich versucht, dies über Templates und void* zu regeln. Aber irgendwie schaffe ich es nie, eine Version zu schreiben, die compilierbar ist.
    Kennt jemand einen Ansatz mit dem so etwas möglich wäre?

    mfg intitled



  • Von der Idee her z.B. so:

    class Container {
    public:
    	template<typename T>
    	void add(T const& obj)
    	{
    		T* cpy = new T(obj);
    		dataPtrs.push_back(cpy);
    	}
    
    	template<typename T>
    	T get(size_t pos)
    	{
    		return *(static_cast<T*>( dataPtrs[pos] ));
    	}
    
    private:
    	std::vector<void*> dataPtrs;
    };
    
    void fill(Container& c){
    	float f = 1.4f;
    	c.add(f);
    	std::string txt = "dfssdfa";
    	c.add(txt);
    	int* ptr = new int(3);
    	c.add(ptr);
    }
    
    int main (int argc, char *argv[])
    {
    	void(*functionPtr)(Container&) = fill;
    	Container c;
    	c.add(functionPtr);
    	c.get<void(*)(Container&)>(0)(c);
    	std::cout<<c.get<float>(1)<<std::endl;
    	std::cout<<c.get<std::string>(2)<<std::endl;
    	std::cout<<*c.get<int*>(3)<<std::endl;
    }
    


  • std::vector<boost::any>



  • Das Problem bei der Variante von for(schlag;den;raab) ist, dass die Typ information verloren geht. Das heißt, du musst wissen, welcher typ in dem Container ist, und den void* zeiger dann dahin gehend reinterpretieren.
    Mir ist eher so eine Lösung vorgeschwebt:

    Container c;
    c.push_back(2.354);
    c.push_back("hello");
    
    cout<<c[0]<<c[1];
    

    Sodass beim Zugriff auf ein Element (muss nicht unbedingt der Indexoperator sein) in den richtigen Typen zurück gecastet wird.

    Wie löst denn boost.any das Problem?



  • Auch bei boost::any musst du den Typ zurückcasten (via boost::any_cast).

    Die einzige Information, die du vorher rausfinden kannst ist die typeid.



  • Intitled schrieb:

    Wie löst denn boost.any das Problem?

    Boost.Any kann selber beliebige Werte beliebiger Typen speichern. Du musst aber immer noch wissen, welcher Typ drinnen steckt!
    Die Doku kennst du ja (link oben). Du musst da immer noch den Typen kennen.
    Einzige Lösung liegt in einem eigenen kleinen Metasystem, wo du Typen registrieren kannst usw, so wie es QVariant hat. Musst du aber selber schreiben, wenn du nicht Qt verwenden willst.


  • Mod

    Es gibt auch noch Boost.Variant



  • Boost::Any sollte so ähnlich aussehen:

    #include <iostream>
    #include <typeinfo>
    
    class holder {
    public:
    	virtual const std::type_info& type() const = 0;
    };
    
    template <typename T>
    struct myholder : public holder {
    	myholder(const T& t)
    		: val(t) { }
    	T val;
    	const std::type_info& type() const {
    		return typeid(val);
    	}
    };
    
    class any {
    private:
    	holder* val;
    public:
    	template <typename T>
    	any(const T& val)
    		: val(new myholder<T>(val)) {
    	}
    
    	~any() { delete val; }
    	const std::type_info& type() const {
    		return val->type();
    	}
    };
    
    int main() {
    	any var = 12;
    	any var2 = 'a';
    	std::cout << "Type ID 1: " << var.type().name() << "\nType ID 2: " << var2.type().name() << std::endl;
    }
    

    Durch virtuelle Funktionen und RTTI ist das aber nicht wirklich schnell.


Anmelden zum Antworten