template spezialisierung
-
Hallo, ich habe eine Frage für template Experten unter euch:
Folgender Code:
template< class ContainerType > class container_resizer { public: void resize( const ContainerType &x , ContainerType &dxdt ) const { if( x.size() != dxdt.size() ) dxdt.resize( x.size() ); } }; template< class ContainerType , class ResizerType = container_resizer<ContainerType> > class ode_step_euler { ContainerType dxdt; ResizerType resizer; public: template< class DynamicalSystem , class TimeType> void next_step( DynamicalSystem system , ContainerType &x , TimeType t , TimeType dt ) { resizer.resize( x , dxdt ); system( x , dxdt , t ); ContainerType::iterator state_begin = x.begin(); ContainerType::iterator state_end = x.end(); ContainerType::iterator derivative_begin = dxdt.begin(); while( state_begin != state_end ) (*state_begin++) += dt * (*derivative_begin++); } };
Der funktioniert soweit auch und ich kann den Code zum Beispiel so benutzen:
ode_step_euler< vector<double> > euler;
Ich möchte nun aber die resizer Klasse auf std::tr1::array<T,N> spezialisieren:
template< class T , int N > class container_resizer< std::tr1::array<T,N> > { public: void resize( const std::tr1::array<T,N> &x , std::tr1::array<T,N> &dxdt ) { } };
Dann sind solche Konstrukte wie
ode_step_euler< array<double,3> > euler;
leider nicht möglich. Nur wenn ich einen expliziten Resizer schreibe und den auch via
ode_step_euler< array<double,3> , array_resizer< array<double,3> > > euler;
angeben. Gibt es eine Möglichkeit soetwas zum umgehen?
-
headmyshoulder schrieb:
Dann sind solche Konstrukte wie
ode_step_euler< array<double,3> > euler;
leider nicht möglich.
Weshalb nicht? Ich seh das Problem nicht gerade.
Übrigens: Ich würde die Schnittstelle wenn möglich bei Spezialisierungen und allgemeinem Template konsistent halten. Das betrifft das
const
beiresize()
.
-
Nexus schrieb:
headmyshoulder schrieb:
Dann sind solche Konstrukte wie
ode_step_euler< array<double,3> > euler;
leider nicht möglich.
Weshalb nicht? Ich seh das Problem nicht gerade.
Ok, hier ist mal der Code, bei dem das Compilieren fehlschlägt.
#include <vector> #include <tr1/array> using namespace std; using namespace std::tr1; // Resizer template< class ContainerType > class container_resizer { public: void resize( const ContainerType &x , ContainerType &dxdt ) const { if( x.size() != dxdt.size() ) dxdt.resize( x.size() ); } }; template< class T , int N > class container_resizer< array< T , N > > { public: void resize( const array<T,N> &x , array<T,N> &dxdt ) const { } }; // Stepper template< class ContainerType , class ResizerType = container_resizer<ContainerType> > class ode_step_euler { ContainerType dxdt; ResizerType resizer; public: template< class DynamicalSystem , class TimeType > void next_step( DynamicalSystem system , ContainerType &x , TimeType t , TimeType dt ) { resizer.resize( x , dxdt ); system( x , dxdt , t ); typename ContainerType::iterator state_begin = x.begin(); typename ContainerType::iterator state_end = x.end(); typename ContainerType::iterator derivative_begin = dxdt.begin(); while( state_begin != state_end ) (*state_begin++) += dt * (*derivative_begin++); } }; // definition of the system void lorenz_vector( const vector<double> &x , vector<double> &dxdt , double t ) { dxdt[0] = 10.0 * ( x[1] - x[0] ); dxdt[1] = 28.0 * x[0] - x[1] - x[0] * x[2]; dxdt[2] = x[0]*x[1] - 2.6666666666 * x[2]; } // definition of the system void lorenz_array( const array< double , 3 > &x , array< double , 3 > &dxdt , double t ) { dxdt[0] = 10.0 * ( x[1] - x[0] ); dxdt[1] = 28.0 * x[0] - x[1] - x[0] * x[2]; dxdt[2] = x[0]*x[1] - 2.6666666666 * x[2]; } int main() { ode_step_euler< vector<double> > euler_vector; ode_step_euler< array< double , 3 > > euler_array; vector<double> xv(3); array<double,3> xa; euler_vector.next_step( lorenz_vector , xv , 0.0 , 0.01 ); euler_array.next_step( lorenz_array , xa , 0.0 , 0.01 ); }
Dann liefert die Ausgabe von
g++
main.cc: In member function ‘void container_resizer<ContainerType>::resize(const ContainerType&, ContainerType&) const [with ContainerType = std::tr1::array<double, 3ul>]’: main.cc:46: instantiated from ‘void ode_step_euler<ContainerType, ResizerType>::next_step(DynamicalSystem, ContainerType&, TimeType, TimeType) [with DynamicalSystem = void (*)(const std::tr1::array<double, 3ul>&, std::tr1::array<double, 3ul>&, double), TimeType = double, ContainerType = std::tr1::array<double, 3ul>, ResizerType = container_resizer<std::tr1::array<double, 3ul> >]’ main.cc:81: instantiated from here main.cc:13: error: ‘struct std::tr1::array<double, 3ul>’ has no member named ‘resize’
Und man sieht, daß beim Anlegen von
euler_array
nicht diearray<T,N>
Spezialisierung verwendet wurde, sondern der Standard-Resizer. Man spezialiert die Resizer Klasse wieder mit einer Template Klasse und das führt zu dem Fehler.Man kann natürlich einen Resizer nur für
array
's schreiben, wietemplate< class T , int N > class array_resizer { public: void resize( const array<T,N> &x , array<T,N> &dxdt ) const { } };
und diesen dann direkt beim Anlegen des Array Steppers angeben:
ode_step_euler< array<double,3> , array_resizer<double,3> > euler_array;
aber das ist halt nicht so user-freundlich. Es wäre schöner, wenn der Compiler entscheiden würde, welcher Resizer verwendet wird.
-
Sehr merkwürdig. Auf MSVC++ kompiliert der Code einwandfrei. Es wird auch wie erwartet die Array-Version aufgerufen.
Versuch mal, den Templateparameter für die Grösse bei der Spezialisierung als
size_t
stattint
zu deklarieren.
-
Nexus schrieb:
Sehr merkwürdig. Auf MSVC++ kompiliert der Code einwandfrei. Es wird auch wie erwartet die Array-Version aufgerufen.
Versuch mal, den Templateparameter für die Grösse bei der Spezialisierung als
size_t
stattint
zu deklarieren.Cool, danke damit funktionierts. Wenn ich das richtig interpretiere ist dann ein
array< class T , int N>
was anderes alsarray< class T , size_t N >
.
-
headmyshoulder schrieb:
Wenn ich das richtig interpretiere ist dann ein
array< class T , int N>
was anderes alsarray< class T , size_t N >
.Ja, das sind zwei verschiedene Templates. Visual C++ scheint es hier aber nicht so genau zu nehmen.