3 Stimmen

C++-Vorlagen: Werte berechnen und Entscheidungen zur Kompilierzeit treffen

Angenommen, Sie haben eine Vektorklasse, die eine Schablonenlänge und einen Schablonentyp hat - d.h. vec<2,float> . Diese können auch verschachtelt werden - vec<2,vec<2,vec<2,float> > > , oder vec<2,vec<2,float> > . Wie tief ein solcher Vektor verschachtelt ist, lässt sich wie folgt berechnen:

template<typename T>
inline int depth(const T& t) { return 0; }
template<int N, typename T>
inline int depth(const vec<N,T>& v) { return 1+depth(v[0]); }

Das Problem ist, dass man erst zur Laufzeit weiß, wie tief es ist, aber man muss die Tiefe zur Komilzeit kennen, um so etwas tun zu können:

// Do this one when depth(v1) > depth(v2)
template<int N, typename T, int M, typename U>
inline vec<N,T> operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return v1 + coerce(v2,v1);
}
// Do this one when depth(v1) < depth(v2)
template<int N, typename T, int M, typename U>
inline vec<M,U> operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return coerce(v1,v2) + v2;
}

Sie können nicht einfach eine "if"-Anweisung einfügen, weil (a) die tiefere Ebene den Rückgabetyp beeinflusst und (b) coerce() einen Erstellungsfehler erzeugt, wenn Sie versuchen, einen verschachtelten Vektor mit einem weniger verschachtelten Vektor zu verknüpfen.

Ist es möglich, so etwas zu tun, oder stoße ich an die Grenzen von C++-Vorlagen?

5voto

Johannes Schaub - litb Punkte 479831

Das ist durchaus möglich. Versuchen Sie zum Beispiel

template<int N, typename T, int M, typename U>
inline typename enable_if<is_deeper<T, U>::value, vec<N,T> >::type 
operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return v1 + coerce(v2,v1);
}

template<int N, typename T, int M, typename U>
inline typename enable_if<is_deeper<U, T>::value, vec<M,U> >::type 
operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return coerce(v1,v2) + v2;
}

Wo is_deeper ist etwa so

/* BTW what do you want to do if none is deeper? */
template<typename T, typename U>
struct is_deeper { static bool const value = false; };

template<typename T, int N, typename U>
struct is_deeper<vec<N, U>, T> { 
  static bool const value = true;
};

template<typename T, int N, typename U>
struct is_deeper<T, vec<N, U> > { 
  static bool const value = false;
};

template<typename T, int N, int M, typename U>
struct is_deeper<vec<M, T>, vec<N, U> > : is_deeper<T, U> 
{ };

3voto

John Dibling Punkte 96619

Die Metaprogrammierung von Vorlagen wird Sie befreien. Ich tue dies zur Laufzeit, aber es wird zur Kompilierzeit ausgewertet:

  #include <iostream>
#include <boost\static_assert.hpp>
using namespace std;

template<size_t Depth> class Vec
{
public:
 enum {MyDepth = Vec<Depth-1>::MyDepth + 1};
};

template<> class Vec<1>
{
public:
 enum {MyDepth = 1};
};

  BOOST_STATIC_ASSERT(Vec<12>::MyDepth == 12);
//  Un-commenting the following line will generate a compile-time error
//    BOOST_STATIC_ASSERT(Vec<48>::MyDepth == 12);

int main()
{
 cout << "v12 depth = " << Vec<12>::MyDepth;
}

EDIT: Ich habe eine statische Boost-Assert eingefügt, um zu zeigen, wie diese zur Kompilierzeit ausgewertet wird.

2voto

Potatoswatter Punkte 130562

Die partielle Spezialisierung ist sehr nützlich für die Introspektion. Normalerweise ist es besser, zu vermeiden inline Funktionen mit konstanten Ergebnissen zur Kompilierzeit. (C++0x könnte dies ein wenig erleichtern, aber ich bin mir nicht sicher, wie sehr).

Erstens: Ihr vec Vorlage sieht ähnlich aus wie boost::array / std::tr1::array / std::array also nenne ich es einfach array .

template< class ArrT >
struct array_depth; // in the general case, array depth is undefined

template< class ElemT, size_t N > // partial specialization
struct array_depth< array< ElemT, N > > { // arrays do have depth
    enum { value = 0 }; // in the general case, it is zero
};

template< class ElemT, size_t N1, size_t N2 > // more specialized than previous
struct array_depth< array< array< ElemT, N1 >, N2 > {
    enum { value = 1 + array_depth< array< ElemT, N1 > >::value }; // recurse
};

// define specializations for other nested datatypes, C-style arrays, etc.
// C++0x std::rank<> already defines this for C-style arrays

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X