Re: EEPROM, C++ a řetěžování operátorů

Miroslav Mraz mrazik na volny.cz
Úterý Květen 30 17:41:20 CEST 2023


Dneska si s tím můžu trochu hrát, to se seznamem parametrů oddělených 
čárkami skutečně jde napsat v šablonách. Já šablony dost nesnáším, ale 
na druhou stranu se vyhodnocují patrně už při překladu, takže by to 
mohlo být efektivnější než rodina printf().

#include <cstring>
#include <cstddef>
#include <iostream>
using namespace std;
/**************************** Balast *******************************/
constexpr int M=4;
struct Params {       // data v EEPROM musí být stejně nějak popsána - 
příklad
   double   a [M];
   unsigned n;
   float    x;
};
static const Params eeprom = {  // tohle by se muselo nějak do EEPROM zapsat
   {1.0, 2.5, 5.0, 10.9},
   1234'5678,
   3.14159f,
};
static bool EEReadBytes (const size_t StartAddr, void * pval, const 
size_t len) {
   cout << "Read from " << StartAddr << ", len=" << len << endl;
   const unsigned char * EEPROM = reinterpret_cast<const unsigned 
char*>(&eeprom);
   return memcpy (pval,  EEPROM + StartAddr, len) == nullptr ? false : true;
}
/***************************** EEPROM ******************************/
template<typename T> class EEVar {    // jednotlivá proměnná
   T data;
   public:
     explicit EEVar (const size_t StartAddr) noexcept {
       EEReadBytes (StartAddr, & data, sizeof(T));
     }
     operator const T () const {
       return data;
     }
};
template<typename T, const int N> class EEArray { // jednorozměrné pole
   T data [N];
   public:
     explicit EEArray (const size_t StartAddr) noexcept {
       EEReadBytes (StartAddr, & data, N * sizeof(T));
     }
     const T & operator[] (const int n) const {
       return data [n];
     }
     // tady by se daly doplnit iterátory třeba pro range based for()
};
/***************************** PRINT ******************************/
template<typename T> void print(const T & t) {  cout << t;  }  // 
poslední parametr končí rekurzi
template<typename First, typename ... Rest> void print(const First & 
first, const Rest & ... rest) {
   cout << first;  print(rest...); // rekurze až do konce - vše, co 
tiskneme musí mít operator<< definován
}
/***************************** MAIN *******************************/
int main () {
   EEVar<unsigned> x(offsetof(Params, n));
   EEVar<float>    r(offsetof(Params, x));
   const float d = 2 * r;                       // počítat s tím jde - 
operator const T dosadí překladač automaticky, pokud nemá jinou možnost
   print("x = ", x, ", d = ", d, "\n");         // ani zde se nemusí 
přetypovat, je to zřejmě jednoznačné
   // pole
   EEArray<double, M> arr(offsetof(Params, a));
   cout << "params: ";                          // pro pole není žádný 
problém, operátor[] je daleko jednoznačnější
   for (int i=0; i<M; i++) print(arr[i], ", ");
   cout << endl;
   // arr[0] = 5.0 // nelze - read only
   return 0;
}

Ani to není tak složité, jen nepřehledné a patrně dost spotřebovává 
zásobník. Kdyby pro AVR fungoval clang, daly by se s tím asi dělat i 
lepší kouzla - třeba parsovat fmt string při překladu. GCC si se 
složitějšími výrazy v constexpr neporadí, dělá to pak v runtime, což je 
otravné a velké.

Mrazík

On 30. 05. 23 1:15, Pavel Hudeček wrote:
> ...
> 
> Co se cout vs prinft týče, tak nejvíc by se mi líbilo něco jako je print 
> v klasickým Basicu, kdy tam napíšu seznam parametrů libovolných typů 
> oddělených čárkama. Vlastně by se toho dalo dosáhnout přetížením 
> operátoru čárka místo <<, jen to bude nestandardně vypadat:-)


Další informace o konferenci Hw-list