Design pattern für unbekannten Typ



  • Wenn du keine Templates haben willst, brauchste wohl Type-Erasure.

    class generic_point
    {
    public:
    	template <class P>
    	generic_point(P p)
    	: impl_(new basic_point<P>(p))
    
    	some_type x()
    	{
    		return impl_->x();
    	}
    
    	// analog y, z etc
    
    private:
    	struct base_point
    	{
    		virtual ~base_point() noexcept = default;
    
    		virtual some_type x() = 0;
    	};
    
    	template <class P>
    	struct basic_point
    	{
    		// constructor
    
    		some_type x() override
    		{
    			return p.x();
    		}
    
    		P p;
    	};
    
    	std::unique_ptr<base_point> impl_;
    };
    

    Den Overhead ist das aber definitiv nicht wert.



  • @volkard: Ja, der Source soll im wesentlichen geheim bleiben. Das Problem bei Algorithmen ist, daß sie aufwändig zu entwickeln, aber leicht zu verstehen sind. Wennst Dein Zeug verkaufen willst, sollten zumindest die Kernkomponenten geheim bleiben. Schlanke Template-Wrapper für den void* pointer hatte ich auch schon im Sinn, danke für die Bestätigung.

    @nathan: Lässige Idee, danke. Overhead ist halt auch ein Thema.



  • was spricht gegen Interfaces?
    die library arbeitet mit abstracten Typen welcher der Benutzer implementieren muss?
    oder verstehe ich das Problem nicht?



  • Hi,

    wofür brauchst du denn einen generischen Punkt für den Benutzer? Das verstehe ich nicht ganz. Was ist das für eine Bibliothek?

    Ich finde, das ist alles Overhead und die Flexibilität, die ihr dadurch meint zu erreichen, erscheint mir als Over-Engineering. Die Generik kostet Performance. Das ist mit einer Template-Lösung noch am wenigsten schlimm, aber wenn ich mir Nathans Lösung so anschaue, dann wieder doch.

    Wenn die Klasse einfach über Koordinaten x,y,z zugreift, dann würde ich den Algorithmus eben einfach so gestalten, schön finde ich das aber nicht, z.B.:

    template<typename Point>
    class SomeAlgo
    {
    public:
        Point add(const Point& a, const Point& b)
        {
            Point c;
            c.x = a.x + b.x;
            c.y = a.y + b.y;
            c.z = a.z + b.z;
            return c;
        }
    };
    

    Da wird aber auch wieder klar, dass x,y,z öffentlich sein müssen und auch nicht als Array implementiert sind, das ist dann also doch wieder implementierungsspezifisch.

    Oder:
    Die low-level-Variante, die aber high-speed ist, ist, dass ihr einfach ein Array von Koordintaen verlangt, der Typ kann ja vom Benutzer vorgegeben werden.

    template<typename CoordType>
    class SomeAlgo
    {
    public:
        std::array<CoordType, 3> addAllPoints(std::vector<CoordType> coords)
        {
            // coords[0] := x1, coords[1] := y1, coords[2] := z1, coords[3] := x2...
    
        }
    };
    

    oder so ähnlich. Wenn der Benutzer jetzt einen struct-Typ ohne Overhead hat, kann er ein Array davon auch einfach umcasten zu einem Array von CoordTypes, das erscheint mir am generellsten... ist aber unschön damit zu programmieren und der Code wird unübersichtlich.

    Also wenn Performance kein ganz großes Anliegen ist, würde ich wohl einfach einen Typ vorgeben.

    Gruß
    E



  • cbook schrieb:

    Gibts passende Design-Pattern für sowas?

    da fällt mir das Adapter-Pattern ein, wobei hier die konkreten Punktklasse des Anwenders die Rolle des Dienstes spielt (s. Link).

    Ansonsten schaue Dir mal die Bibliothek boost.polygon an. Die haben das identische Problem, was Du auch hast. Die Lösung besteht in einer Spezialisierung Bibliothekseigener Templates mit der konkreten User-Klasse - z.B.: http://www.boost.org/doc/libs/1_56_0/libs/polygon/doc/gtl_point_concept.htm


  • Mod

    Nathans Lösung ist ja auch einfach inperformant. Ordentliche Type-Erasure sieht man hier: http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates



  • am einfachsten ist wohl ein möglichst C-like interface aufzubauen wo der Benutzer die Daten einfach als double* übergibt (mit 3*n elementen für n Punkte). Und dann dazu noch nen hübscher C++ wrapper für eure Lieblingstypen, fertig.



  • Gerade ist mir eine Lösung eingefallen, die den Algo-Code verbergen kann und sauschnell bleibt. *freu* 😃

    Werner Salomon schrieb:

    http://www.youtube.com/watch?v=UU_mL0dOqlw (Bernd Brot: "Mist")



  • Arcoth schrieb:

    Nathans Lösung ist ja auch einfach inperformant. Ordentliche Type-Erasure sieht man hier: http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates

    Nathans Lösung ist die Standardlösung.
    Der Artikel den du verlinkst macht in diesem Zusammenhang auch keinen Sinn, da dabei keine unterschiedlichen Objekte in der generischen Klasse gespeichert werden. Das ist nämlich die Schwierigkeit bei der Sache.



  • @cbook
    Dein Denkfehler ist dass du die Klasse als Container für Objekte beliebigen Typs siehst, die die Attribute X, Y und Z haben.
    Sieh die Klasse lieber als Spatialen Index, in dem du zu einem XYZ-Triplet (Key) einen Wert ablegen kannst.
    Und der Wert muss nicht unbedingt generisch sein. Eine Implementierung mit void* oder size_t ist vollkommen ausreichend.

    Wie volkard schon schreibt...

    volkard schrieb:

    Kein Problem: Um die geheime void*-Lib kannste untraschlanke Template-Wrapper anbieten, die per static_cast für den User T* draus machen.


Anmelden zum Antworten