понедельник, 27 августа 2018 г.

Curiously Recurring Template Pattern (CRTP)

https://ru.wikipedia.org/wiki/Странно_рекурсивный_шаблон

#include <iostream>  
 
using namespace std;  
 
template<typename T>  
class BaseSinglton  
{  
    protected:  
        BaseSinglton() {}  
        virtual ~BaseSinglton() {}
    public:  
        static T& instance()   
        {
            static T oObj;   
            return oObj;   
        }
};  
 
class Settings : public BaseSinglton<Settings>  
{  
    friend class BaseSinglton<Settings>;  
    private:  
        Settings() : BaseSinglton<Settings>() {}  
        virtual ~Settings() {}  
};
 
int main()   
{  
    Settings &oSetting = Settings::instance();  
    printf("poSetting = %p", &oSetting);  
    return 0;  
}  

воскресенье, 26 августа 2018 г.

Псевдозамыкания на С

 #include <stdio.h>  
 #include <stdlib.h>  
 #include <stdarg.h>  

static int _dump(char *psDstBuf_      , size_t nSizeDstBuf_, 
                 const void *pSrcBuf_ , size_t nSizeSrcBuf_)  
{  
    const char aHexSymbol[] = { 
                                '0', '1', '2', '3', '4', '5', '6', '7',
                                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 
                              };  
    size_t iSrcBuf = 0;  
    size_t iDstBuf = 0;  
    unsigned char cByte = '\0';

    if ( nSizeDstBuf_ < 3 ) { return 0; }
  
    for (iSrcBuf=0; iSrcBuf<nSizeSrcBuf_; ++iSrcBuf) {
      if ( ( nSizeDestBuf_ - iSrcBuf * 3 ) < 3 ) { break; }
      cByte = ((const unsigned char*) pSrcBuf_)[iSrcBuf];
      psDstBuf_[iDstBuf++] = aHexSymbol[(cByte >> 4) & 0b1111];
      psDstBuf_[iDstBuf++] = aHexSymbol[cByte & 0b1111];
      psDstBuf_[iDstBuf++] = ( (iSrcBuf & 0b1111) == 0b1111) ? '\n' : ' ';
    }

    psDstBuf_[iDstBuf ? iDstBuf - 1 : 0] = '\0';

    return ( iSrcBuf * 3 );  
}

#define LOG(fBufFiller, nSizeData)                        \
({                                                        \  
    char *psDumpMessage = (char*) calloc(nSizeData, 1);   \  
                                                          \
    fBufFiller(psDumpMessage);                            \
                                                          \
    printf("%s", psDumpMessage);                          \
                                                          \
    free(psDumpMessage);                                  \
})
  
static void _message_error(const char *psFormat_, ...)  
{  
    va_list nArgs;

    va_start(nArgs, psFormat_);  
    size_t nSizeMsg = vsnprintf(NULL, 0, psFormat_, nArgs);  
    va_end(nArgs);  
    
    #define fBufFiller(psBuf)                \
    ({                                       \
        va_start(nArgs, psFormat_);          \
        vsprintf(psBuf, psFormat_, nArgs);   \
        va_end(nArgs);                       \
    })
  
    LOG(fBufFiller, nSizeMsg);
  
    #undef fBufFiller  
}

static void _message_dump(void *pDataDump_, unsigned int nSizeDump_)  
{  
    const size_t nSizeBuf = nSizeDump_ * 3;  
    
    #define fBufFiller(psBuf)                             \
    ({                                                    \
        _dump(psBuf, nSizeBuf, pDataDump_, nSizeDump_);   \  
    })

    LOG(fBufFiller, nSizeBuf);

    #undef fBufFiller  
}

static void _message_state_report(int iModule_, int nError_)  
{  
    const size_t nSizeBuf = 64;
 
    #define fBufFiller(psBuf)                                              \
    ({                                                                     \
        const char *psState = nError_ ? "unworkable" : "workable";         \
        sprintf(psBuf, "Report for module #%d: %s ", iModule_, psState);   \  
    })

    LOG(fBufFiller, nSizeBuf);

    #undef fBufFiller  
}

int main(void)  
{  
    int aRandomData[] = { 9, 8, 7, 6, 5 };

    _message_error("Sending packet '%s' is failed (code error: %d)", "bpdu_tcn", 3);  
    printf("\n\n");  

    _message_state_report(3, 5);  
    printf("\n\n");  

    _message_dump(aRandomData, sizeof(aRandomData));  
    printf("\n\n");  
    
    return 0;
}

воскресенье, 5 августа 2018 г.

Именованные параметры. K-Macros

https://blog.tartanllama.xyz/simple-named-bools/

При вызове функции типа

 cake make_cake (bool with_dairy, bool chocolate_sauce, bool poison)  

явна видно проблема ненаглядности передаваемых параметров и, как следствие, отсутствие понимания намерений програмиста.

 auto c = make_cake(true, true, false);  

Что означает первый true, второй true и третий false ? Совершенно непонятно и надо заглядывать в определение функции.

Для разрешения данной проблемы можно использовать следующий подход

 const bool with_dairy      = true;  
 const bool chocolate_sauce = true;  
 const bool poison          = false;  
 auto c = make_cake(with_dairy, chocolate_sauce, poison);  

Недостаток очевиден - введены три переменные, абсолютно ненужные для правильного исполнения кода, исключительно для улучшения читабельности. Дополнительно происходит 'раздутие' кодовой базы - вместо 1 строчки получается 4 строчки.

Можно попробовать и так

 auto c = make_cake(  
                     true  /* with_dairy      */,   
                     true  /* chocolate_sauce */,   
                     false /* poison          */  
                   );   

Лишних переменных нет, но также происходит 'раздутие' кодовой базы.

Данное затруднение является частным случаем того, что в языках С/С++ нет нативной поддержки так называемых именованных параметров. Много способов разрешить данную проблемы содержится в статье - https://habr.com/company/infopulse/blog/246663/. Также имеется мнение, что, по крайней мере в С++, именованные параметры в общем случае и не нужны - https://habr.com/post/246711/.

Simon Brand (blog.tartanllama.xyz) предлагает свое решение

 #define K(name) true  
   
 auto c = make_cake(K(with_dairy), !K(chocolate_sauce), !K(poison));  

Преимуществом является относительная наглядность, отсутствие 'раздутия' кодовой базы.
Недостатком является некоторая необычность синтаксиса.