Pull to refresh

Comments 9

  1. Прозрачное сравнение это же не обязательно под строки? Концепт, подходящий только под частный случай — как-то не ок.

  2. Почему вообще код (ниже процитирован код из статьи) закладывается на то, что K — это std::string?

template <typename K>
void insert(K&& key) {
    using CleanKey = std::remove_cvref_t<K>; // Удалили const, &, volatile
    static_assert(std::is_same_v<CleanKey, std::string>, "Должен быть std::string!");
    // ...
}
  1. Эээ.. Каким образом это вообще insert? Да, что вы разошлись — тут вы правы

  void insert(Key key, Value value) {
      std::atomic_ref<Key>(key).store(key);
  }

Это если по поверхности пройтись.

  1. Тут нет никакой оптимизации для trivially copyable. У вас тут буквально семантически эквивалентный код. Семантически эквивалентный, но вы во втором случае зачем-то делаете бесполезный piecewise construct.

template <typename K>
void insert(K&& key, Value&& value) {
    if constexpr (std::is_trivially_copyable_v<Value>) {
        // Быстрая вставка для простых типов (int, double и т.д.)
        buckets.emplace_back(std::forward<K>(key), std::forward<Value>(value));
    } else {
        // Медленная, но безопасная для сложных типов
        buckets.emplace_back(std::piecewise_construct,
                           std::forward_as_tuple(std::forward<K>(key)),
                           std::forward_as_tuple(std::forward<Value>(value)));
    }
}

4) да, я тут поглядел и фигню написал. Можно спокойно сжать до

template <typename K>
void insert(K&& key, Value&& value) {
    buckets.emplace_back(std::forward<K>(key), std::forward<Value>(value));
}

И этого будет достаточно.

Тут видимой была бы эффективность piecewise_construct при конструировании std::pair или std::tuple из нескольких аргументов, что бы избежать лишних промежуточных копирований и перемещений.

Так то, что бы просто показать работу if constexpr можно разделить на передачу для маленьких тривиально копируемых типов (без piecewise_construct) и для нетривиальных типов (с piecewise_construct).
Для больших тривиально копируемых типов скорее всего не будет смысла делать, т.к. разница будет практически незначительной.
Ну даже так отрывок кода выше будет прекрасно справляться.

p.s. Благодарю за замечание.

1-2) вы в праве реализовать это так, как вам угодно, вы ничем не ограничены. Это лишь моя идея их реализации.
3) Это абстрактный пример, конечно, его можно подогнать под более реальную версию insert, я просто посчитал, что для демонстрации идеи этого будет достаточно.

У меня вопрос про [[no_unique_address]]
А нет ли в компиляторах реализации своих кастомных атрибутов для до c++20 эпохи, так чтобы я мог наделать макросов и использовать [[no_unique_address]] фичу в c++17?

Ну на самом деле в 17 такого нет, насколько мне вообще известно, но если вам важно определить - сжимаем ли объект, то вы можете это сделать через наследование (EBO)

https://en.cppreference.com/w/cpp/language/ebo

struct Empty {};

struct S : private Empty {  // EBO
    int x;
};
static_assert(sizeof(S) == sizeof(int));

Конечно, это вообще никак не замена, но к сожалению других способов я не знаю. Если найдете, то буду рад послушать.

Забыл совсем про такое, но единственное - придется юзать boost, возможно не всем подойдет. Было бы хорошо, если проект изначально бы использовал boost)

Подумал было, что это уже должно работать в стандартном `std::tuple`, но как оказалось оно implementation defined. Плюс для msvc EBO оказывается нужно включать специально.
Пример https://godbolt.org/z/dhEGfqnbz

Sign up to leave a comment.

Articles