пятница, 26 января 2024 г.

[prog.c++] Интересное чтиво про strict aliasing rule...

...лежит здесь: What is the Strict Aliasing Rule and Why do we care?

Документ далеко не новый, но если вы не в теме, то он будет, безусловно, полезен.

Из того, что стало откровением и открытием лично для меня (применительно к C++):

  • в C++ содержимое другого объекта можно просматривать путем каста к char, unsigned char или std::byte. Т.е., грубо говоря, вы всегда можете сделать reinterpret_cast<char *>(other_pointer). Но это не распространяется на signed char. И отдельная история с std::int8_t/uint8_t: эти типы могут быть простыми синонимами для char и unsigned char, а могут быть и отдельными, самостоятельными типами (в таком случае на них правило char/unsigned char/std::byte не распространяется);
  • оказывается, современные компиляторы могут понять, что делает std::memcpy и избавиться от реального вызова std::memcpy. Например, вот такой корректный способ получить float из int-а (при условии их одинаковых размеров):

    int src = ...;
    float dst;
    std::memcpy(&dst, &src, sizeof(src));

    в случае умного компилятора будет просто помещать в dst нужно значение без вызова memcpy;

  • не знал раньше про common initial sequence. А это, как выяснилось, может стать архиважной штукой при работе с union:

    struct A { char type; ... };
    struct B { char type; ... };
    struct C { char type; ... };
    union U { A a; B b; C c; };
    
    U u;
    u.a = ...;
    if(u.b.type == ...) // (1)
    {...}

    Обращение к u.b в точке (1) легально не смотря на то, что U::b -- это неактивный в данный момент элемент union-а.

понедельник, 22 января 2024 г.

[prog.c++] Оказывается, в современном C++ параметры шаблона с дефолтными значениями можно располагать в начале списка параметров шаблона...

Был приятно удивлен тому, что вот это вполне себе компилируется и работает так, как мне и нужно:

#include <iostream>

struct no_size_limit {
    static bool is_size_valid(std::size_t /*size*/) {
        std::cout << "no_size_limit::ensure_valid_size" << std::endl;
        return true;
    }
};

template<typename Size_Limiter=no_size_limit, typename... Args>
void f(Args && ...args) {
    if(Size_Limiter::is_size_valid(sizeof...(args))) {
        std::cout << "processing of args" << std::endl;
    }
    else
        std::cout << "ignoring args" << std::endl;
}

template<std::size_t N>
struct at_least {
    static bool is_size_valid(std::size_t size) {
        std::cout << "at_least<" << N << ">::ensure_valid_size" << std::endl;
        return (N <= size);
    }
};

int main() {
    f(12345);
    f<at_least<3>>(12345);
    f<at_least<5>>(123);
}

Цынк

Так-то я со времен C++98 привык, что параметры шаблона со значениями по умолчанию идут в конце списка параметров шаблона. А тут потребовалось, чтобы они шли в начале. И оно раз и заработало.

Приятно.


На правах саморекламы: изобретаю велосипеды для себя, могу изобретать и для вас.