Forum: Mikrocontroller und Digitale Elektronik Template Ableitung


von cpp Frager (Gast)


Lesenswert?

Hallo,
da hab ich mal eine Frage zu cpp Templates.

ich möchte mir eine CRC Berechnungsklasse bauen.
Alleine vom eingereichten CRC Model soll diese wissen ob sie CRC8/16/32 
berechnen soll.
Also Templates!

Nur muss ich von einem Template auf verschiedene Variablen Templates 
schließen und bisher hab ich nicht gefunden wie das gehen soll.

Hier mal als Code was ich will:
1
template <class crcType>
2
class CrcCalc
3
{
4
5
public:
6
7
    //! constructor to initalize object
8
    CrcCalc(crcType *p_crc);
9
    
10
    //! virtual destructor
11
    virtual ~CrcCalc();
12
    
13
    //! \brief calculates the CRC over the given block
14
    //! \param[in] p_data Pointer do data to be CRC calculated
15
    //! \param[in] bytes number of bytes to calculate over
16
    //! \return CRC checksum
17
    virtual crcWidth Block(void *p_data, uint32_t bytes);
18
    
19
private:
20
    
21
    //! \brief variable that holds the CRC Model
22
    crcType *mp_crcType;
23
    
24
    //! Variable that holds internal CRC calculation data
25
    crcCalc m_crcImmediates;
26
    
27
};

Also von "crcType" möchte ich auch auf "crcCalc" und "crcWidth" 
schließen können.

crcType kann sein:
-struct crc8
-struct crc16
-struct crc32

crcWidth soll dann sein:
-uint8_t
-uint16_t
-uint32_t

Also wie wär das möglich?

Natürlich könnt ich jetzt schreiben:
template <class crcType, class crcCalc, class crcWidth>
Aber das will ich vermeiden.

von Sven P. (Gast)


Lesenswert?

Mit Spezialisierung des Templates.
Oder In einem Template mit SFINAE.

Ersteres ist die banalste Grundlage bei der Verwendung von Templates, 
findest du also eigentlich in jedem Buch oder in jedem Tutorial.

von cpp Frager (Gast)


Lesenswert?

Das kenn ich durchaus, aber dann muss ich die Klasse 3 mal 
implementieren (einmal für jede Speziallsierung).
Genau das will ich ja vermeiden, da sich diese nur über die 
Variablenbreite der temporären Variablen unterscheiden.

(Und dann kann ich auch gleich C nehmen)

SFINAE sieht auf den ersten Blick aus wie Overloading, nur etwas anders.
https://en.cppreference.com/w/cpp/language/sfinae
Ich guck mal.

von Cyblord -. (cyblord)


Lesenswert?

IMO missbrauchst du hier die Funktion eines Template. Sinn und Zweck bei 
einem Template besteht darin, dass der Klasse der Typ prinzipiell egal 
ist. Man möchte die gleichen Operationen auf verschiedenartigsten Typen 
zulassen. Beispiele sind hier Listen, Vektoren, Bäume usw.

Dir ist der Typ aber gerade nicht egal, denn der Typ bestimmt erst die 
tatsächliche Operation. D.h. je nach CRC Typ musst du eine andere 
Funktion, mit auch noch anderen Parametern aufrufen. Wo sind jetzt 
überhaupt noch Gemeinsamkeiten die du generalisieren willst?

von Maximilian (Gast)


Lesenswert?

https://www.boost.org/doc/libs/1_71_0/doc/html/crc.html
> The Boost.CRC library provides access to two styles of CRC computation, one as a 
function template, the other as a function template and two computation object 
class templates, where the two class templates differ in speed.

von Thomas W. (goaty)


Lesenswert?

Eventuell könntest du es umbauen, daß der Templateparameter der unterste 
Datentyp ist (int8,16, 32) und die evtl. notwendigen "struct" in der 
Klasse selbst definierst.

Was sind denn crcCalc für typen ?

template <class T>
class OBJ
{
public:
  struct S {
    T data;
  };
  OBJ(const T& t): myData(t) {}

private:
  T myData;
};

von cpp Frager (Gast)


Lesenswert?

crcCalc ist ein struct was im Endeffekkt auch nur uint enthält.
zB ein Pointer auf die XOR Tabelle oder den Startwert sowie den 
aktuellen CRC Wert (wenn man in kleinen Blöcken rechnet) und ob am Ende 
nochmal invertiert werden soll.
Das crcCalc selbst ließe sich also auchnoch templaten.

Aber wies aussieht geht die meinung in die Richtung, dass Templates hier 
falsch sind.
Das geht wohl nur für Funktionen die nichts typabhängiges 
zwischenspeichern müssen.

Also beiß ich in den sauren Apfel und mach 3 Implementierungen vom 
selben Interface.

von Thomas W. (goaty)


Lesenswert?

Geht das nicht irgendwie so wie ich gemeint hab ?


template <class BasisTyp>
class CrcCalc
{

public:
    struct crcType {
      BasisTyp data;
      // und was noch so in die struct soll
    }
    struct crcCalc {
      BasisTyp data;
      // und was noch so in die struct soll
    }


    //! constructor to initalize object
    CrcCalc(crcType *p_crc);

    //! virtual destructor
    virtual ~CrcCalc();

    //! \brief calculates the CRC over the given block
    //! \param[in] p_data Pointer do data to be CRC calculated
    //! \param[in] bytes number of bytes to calculate over
    //! \return CRC checksum
    virtual BasisTyp Block(void *p_data, uint32_t bytes);

private:

    //! \brief variable that holds the CRC Model
    crcType *mp_crcType;

    //! Variable that holds internal CRC calculation data
    crcCalc m_crcImmediates;

};

von cpp Frager (Gast)


Lesenswert?

Ob das geht wäre jetzt zu experimentieren.
Von "struct crcType" muss es ja mehrere geben, denn es gibt ja CRC16 
schon mit mehreren Polynomen wie 0x8005 und 0x1021.
Dann muss das ja noch mitübergeben werden und ob am Ende invertiert wird 
oder nicht sowie den Startwert.

Daher wollte ich es ja von diesem Typ abhängig machen und auf die 
restlichen schließen.
Da müsst man wohl mal Bjarne eine Mail schreiben damit das bei cpp mal 
reinkommt.

@Maximilian:
Bei der Boost lib wird ja auch ALLES per templates reingereicht, ich seh 
da bis zu 5 templated Variablen pro Funktionsaufruf.
1
crc_32 = boost::crc<bits, TruncPoly, InitRem, FinalXor,
2
                   ReflectIn, ReflectRem>(blah, keks)
(Also das hab ich jetzt auf die schnelle als Aufruf gefunden)

von Vincent H. (vinci)


Lesenswert?

Mit ein wenig meta programming geht das schon.
https://godbolt.org/z/-CyWtI

Das sagt dem Compiler im Prinzip bei
Crc8 -> uint8
Crc16 -> uint16
Crc32 -> uint32
zu benutzen.

Ich frag mich jedoch wieso du diese Information nicht im CrcType 
hinterlegst? Schau dir mal an wie die STL aufgebaut ist.

Ich würde den CrcType selbst als Template anlegen und die CrcWidth 
Information da drin ablegen.
1
template<typename T>
2
struct CrcType {
3
  using CrcWidth = T;
4
};
5
6
using Crc8 = CrcType<uint8_t>;

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.