Zusätzlicher Konstruktor durch Partielle Spezialisierung



  • template<typename T, int size>
    struct vec
    {
    	T v[size];
    
    	T getLength()
    	{
    		return 1;
    	}
    };
    
    template<typename T>
    struct vec<T, 3>
    {
    	vec()
    	{
    	}
    	vec(T x, T y, T z)
    	{
    	}
    };
    
    typedef vec<float, 2> vec2f;
    typedef vec<float, 3> vec3f;
    typedef vec<float, 4> vec4f;
    

    ich will das mein vec3f zusätzlich zu den üblichen Methoden die ein vec anbietet auch noch zwei Konstruktoren bereit stellt.

    folgendes sollte möglich sein:

    vec3f t(7,8,1);
    t.getLength();
    

    geht aber nicht weil Compiler meint:

    'getLength' : is not a member of 'vec<T,size>'
    

    das ist doch ganz schön blöde wenn ich jetzt nochmal alle Methoden von vec in der partiellen Spezialisierung von vec<T,3> noch mal neu programmieren muss - kann ich nicht einfach die ganze Funktionalität von vec haben und zusätzlich einfach noch die zwei Konstruktoren - ich habe versucht von vec zu erben - aber funzt nicht



  • Muss aber funzen. Die Signaturen der Konstruktoren hängen (selbstverständlich) von der Deklaration in der Klasse ab. D. h., entweder du spezialisierst die gesamte Klasse, oder du leitest ab (schlauer) und spezialisierst die Ableitung.

    Ich probier gleich ein wenig mit Ableitung rum. Warte mal.



  • Na wieso, geht doch wunderbar:

    template<typename T, int size>
    struct base_vec
    {
        T v[size];
    
        virtual T getLength()
        {
            return 1;
        }
    };
    
    template<typename T, int size>
    struct vec : public base_vec<T, size> ///Das Klassentemplate
    {
    };
    
    template<typename T>
    struct vec<T, 3> : public base_vec<T, 1> ///Spezialisierung
    {
        vec(){}
        vec(T , T, T){}
    };
    

    Ideone: http://ideone.com/0Pphs


  • Mod

    Soll vec für size!=3 ein Aggregat sein?



  • camper schrieb:

    Soll vec für size!=3 ein Aggregat sein?

    Ja, irgendwie sehe ich hier keinen Sinn. Das ist doch vom Design her total verkorkst.

    Ich meine, eigentlich sollte man doch Klassentemplates nie Spezialisieren, mir ist noch nie ein gutes Beispiel begegnet 😕



  • Wenn du C++11 verwenden kannst, kannst du gleich eine allgemeine Vektorklasse schreiben, die das für alle Grössen kann.

    template <typename T, unsigned S>
    struct vec {
      T v[S];
    
      T const* begin() const { return v; }
      T const* end()   const { return v+S; }
    
      auto length() const -> decltype(std::sqrt(std::declval<T>()))
      {
        auto square = [](T const& a, T const& b){return a+b*b;};
        T sum_of_squares = std::accumulate(begin(), end(), T{}, square);
        return std::sqrt(sum_of_squares);
      }
    };
    
    int main()
    {
      vec<int, 3> v = {{2,1,2}};
      std::cout << v.length() << '\n';
    
      vec<int, 2> v2 = {{6,8}};
      std::cout << v2.length() << '\n';
    }
    

    http://ideone.com/P61fX

    BTW: Lol Sone, immerhin merkst du selber dass dein Code keinen Sinn hat.
    Wobei man auch bei meinem Code aufpassen muss, da vec jetzt immer in einem Aggregatzustand ist.



  • .
    Mein Code ist auf seine Frage eingegangen, der Sinn sei mal dahingestellt.



  • Dass vec eine n-dimensionale Koordinate repräsentiert, hat auch keiner gesagt.



  • Also dass vec für Vektor steht, sollte klar sein. Und ein Vektor ist stets in einem Vektorraum, von daher finde ich den Einwand sehr fragwürdig.



  • Eisflamme schrieb:

    Also dass vec für Vektor steht, sollte klar sein. Und ein Vektor ist stets in einem Vektorraum, von daher finde ich den Einwand sehr fragwürdig.

    Nein, ein Vektor ist einfach eine Ansammlung von Werten. Diese können dann entsprechend Interpretiert werden (bspw. als Array/Liste von Werten, als Koordinaten, usw. usw.).



  • Sone schrieb:

    Na wieso, geht doch wunderbar:

    virtual ~base_vec(){}
    

    🙄



  • hustbaer schrieb:

    Sone schrieb:

    Na wieso, geht doch wunderbar:

    virtual ~base_vec(){}
    

    🙄

    Ja, das ist Bullshit. Editiert.

    Der TE müsste sich jetzt langsam mal melden.


  • Mod

    Variante, bei der das allgemeine Template ein Aggregat bleibt.

    template <typename T, std::size_t N>
    struct vec_generic
    {
        T v[N];
    ...
    };
    
    template <typename T>
    struct vec3 : vec_generic<T, 3>
    {
        vec3();
        vec3(T, T, T);
    ...
    };
    
    template <typename T, std::size_t N>
    struct vec_
    {
        typedef vec_generic<T, N> type;
    };
    
    template <typename T>
    struct vec_<T, 3>
    {
        typedef vec3<T> type;
    };
    

    Verwendung dann mit vec_<T,N>::type oder wenn Aliastemplates zur Verfügung stehen:

    template <typename T, std::size_t N>
    using vec = vec_<T, N>::type;
    

    Optionaler Konstruktor:

    template <typename T, std::size_t N>
    struct vec
    {
        T v[N];
        vec();
        template <typename U, typename V, typename W>
        vec(U, V, W, typename boost::enable_if<typename boost::mpl::and_<boost::mpl::bool_<boost::is_convertible<U, T>::type::value
                                                                                        && boost::is_convertible<V, T>::type::value
                                                                                        && boost::is_convertible<W, T>::type::value>, boost::mpl::bool_<N==3>>::type>::type* = 0);
    
    // mit C++11
        template <std::size_t I = N, typename std::enable_if<I==3, int>::type = 0>
        vec(T, T, T);
    
    // mit C++11 allgemein
        template <typename... U, typename std::enable_if<sizeof...(U)==N, int>::type = 0>
        vec(U&&... u) : v{ std::forward<U>(u)... } {}
    };
    

Log in to reply