2016-03-23 8 views
2

Ich fragte mich, was ist der beste Weg, um Zugriff auf eine size_t Template-Parameter, so dass ich es in eine andere Template-Klasse (also nicht über eine Methode Aufruf) übergeben kann. Zum Beispiel, wenn ich die Klassen,Extrahieren size_t Template-Parameter

template<typename T, size_t D> class Point; 
template<typename T> class Line; 

template<typename T, size_t D> 
class Shape 
{ 
    public: 
    virtual size_t dims() const = 0; 
    virtual bool intersects(Point<T,D> p) const = 0; 
    virtual bool intersects(Line<Point<T,D>> l) const = 0; 
} 

template<typename T, size_t D> 
class Point : Shape<T,D> 
{ 
    public: 
    typedef T type; 
    size_t dims() const {return D;} 
    type val(size_t d) {return vals[d];} 
    bool intersects(Point<T,D> p) 
    { 
    for(size_t d=0; d<D; ++d) if(p.vals[d] != vals[d]) return false; 
    return true; 
    }  

    bool intersects(Line<Point<T,D>> l) 
    { 
    return l.intersects(*this); 
    } 

    protected: 
    type vals[D]; 
}; 

// How do I get D??? 
template<typename Point_t> 
class Line : public Shape<typename Point_t::type,??> 
{ 
    public: 
    typedef typename Point_t::type type; 
    size_t dims() const {return point.dims();} 

    bool intersects(Point<type,??> p) {/*stuff*/}  
    bool intersects(Line<Point_t> l) {/*stuff*/} 

    private: 
    Point_t point; 
    type slope; 
}; 

Ich mag die intersects Methode innerhalb Linie, um sicherzustellen, nur für eine Linie arbeitet einen Punkt mit den gleichen Abmessungen schneidenden (verhindern 3D-Linie 2D-Punkt schneiden). Ich dachte darüber nach, dass Line die gleichen Parameter wie Point verwendet, aber dann würde der Compiler keine Fehler finden, wie beispielsweise eine kartesisch definierte Linie mit einem sphärisch definierten Punkt zu schneiden (da beide Point<double,3> sind). Mit dem, was ich oben habe, kann ich kartesische und sphärische Klassen definieren, um dieses Problem zu vermeiden.

template<typename T, size_t D> class Cartesian : public Point<T,D>{/*stuff*/} 
template<typename T> class Spherical : public Point<T,3> {/*stuff*/} 

Line<Cartesian<double,3>> Line; 
Cartesian<double,3> C3Point; 
Cartesian<double,2> C2Point; 
Spherical<double> SPoint; 
Line.intersects(C3Point); // ok 
Line.intersects(C2Point); // compiler error 
Line.intersects(SPoint); // compiler error 

edit: , was ich zur Zeit, die funktioniert, besteht darin, die Linie Klasse als

template<typename Point_t, size_t D> 
class Line : public Shape<typename Point_t::type,D> 
{/*stuff*/} 

definieren, sondern enthält redundante Informationen ...

Line<Cartesian<double,3>,3> Line; 

Antwort

2

In C++ 11, Sie können drehen

size_t dims() const {return D;} 

i

nto
static constexpr size_t dims() {return D;} 

Und so

template<typename Point_t> 
class Line : public Shape<typename Point_t::type, Point_t::dims()> {..}; 
+0

Die zweite behandelt nicht das Beispiel von OP. –

+0

@ T.C .: Das sah ich einfach. – Jarod42

+0

Brauchen Sie 'typename' nicht vor' Point_t :: type'? –

0

Ich glaube, ich es herausgefunden. Mein tatsächlicher Code ist komplizierter als das Beispiel (weshalb ich es für schwieriger hielt, die Lösung zu sehen), aber diese grundlegende Methode funktionierte. Ich umstrukturiert meine Klassen, wie unten,

template<typename T> class Line; 

template<typename T, size_t D> 
class Point 
{ 
    public: 
    typedef T type; 
    size_t dims() const {return D;} 
    type val(size_t d) {return vals[d];} 
    bool intersects(Point<T,D> p) 
    { 
    for(size_t d=0; d<D; ++d) if(p.vals[d] != vals[d]) return false; 
    return true; 
    }  

    bool intersects(Line<Point<T,D>> l) 
    { 
    return l.intersects(*this); 
    } 

    protected: 
    type vals[D]; 
}; 

template<typename T> 
class Shape 
{ 
    public: 
    typedef T Point_t; 
    virtual size_t dims() const = 0; 
    virtual bool intersects(Point_t p) const = 0; 
    virtual bool intersects(Line<Point_t> l) const = 0; 
} 

template<typename Point_t> 
class Line : public Shape<Point_t> 
{ 
    public: 
    typedef typename Point_t::type type; 
    size_t dims() const {return point.dims();} 

    bool intersects(Point_t p) {/*stuff*/}  
    bool intersects(Line<Point_t> l) {/*stuff*/} 

    private: 
    Point_t point; 
    type slope; 
}; 

Nun sind die folgenden Arbeiten wie erwartet,

template<typename T, size_t D> class Cartesian : public Point<T,D>{/*stuff*/} 
typedef Cartesian<double,3> Cartesian3D; 
typedef Cartesian<double,2> Cartesian2D; 
template<typename T> class Spherical : public Point<T,3> {/*stuff*/} 

Line<Cartesian3D> Line; 
Cartesian3D CPoint3D; 
Cartesian2D CPoint2D; 
Spherical<double> SPoint; 
Line.intersects(C3Point); // ok 
Line.intersects(C2Point); // compiler error 
Line.intersects(SPoint); // compiler error 

Grundsätzlich, ich Punkt nicht als eine Form sein. Wenn ich das tue, brauche ich die Shape-Klasse nicht, um D zu kennen, und alles, das von Shape abgeleitet ist, enthält einen Point_t, von dem ich die Dimensionen erhalten kann. Ich muss nur daran denken, für jede von Shape abgeleitete Klasse Schnittmethoden explizit in die Point-Klasse einzufügen.