Pull to refresh
2
Андрей Давыдов@AndDav

Пользователь

Send message

Как пользоваться гетерогенным поиском в set/map/… просто и давно известно — передаешь std::less<> вторым/третьим шаблонным аргументом и все само заработает, это все кому было интересно с 2014-го уже узнали. А вот, про unordered контейнеры информация
1) свежая и поэтому пока малоизвестная,
2) более сложная — просто передать std::-что-нибудь не получится,
но, к сожалению, именно про это в статье ничего — ни примеров, ни теории, нет.

На ваш взгляд, каким должен быть совершенный цикл в 2020м году?
Примерно таким, как у вас в статье, только в C++20 (23) можно использовать стандартные функции вместо самописных. range -> iota (https://gcc.godbolt.org/z/d3bqYK). enumerate и zip должны появиться в C++23, так это выглядит в range-v3 (https://gcc.godbolt.org/z/9EfMj5):
#include <range/v3/view/enumerate.hpp>
#include <range/v3/view/zip.hpp>

#include <vector>

void test(std::vector<int> xs, std::vector<float> ys) {
    for (auto [x, i] : ranges::view::enumerate(xs)) {
        // ...
    }
    for (auto [x, y] : ranges::view::zip(xs, ys)) {
        // ...
    }
}
Вместо вложенных циклов можно (но не факт что нужно) использовать cartesian_product (https://gcc.godbolt.org/z/vaasqq):
void test(std::vector<int> xs, std::vector<float> ys) {
    for (auto [x, y] : ranges::view::cartesian_product(xs, ys)) {
        // ...
    }
}

На счет поддержки C++ не правда. Поддержка C++20 появляется в GCC не позже чем в Clang-е. И почему это libc++ — "наиболее полная реализация стандартной библиотеки C++", чем libstdc++ хуже (в libstdc++ к примеру уже есть Ranges)? Да, Richard Smith работает над Clang-ом, зато LWG chair Jonathan Wakely работает над GCC. В целом в комитете по стандартизации разработчики GCC и Clang-а представлены одинаково.

Ок, давайте поиграем в игру "в интернете кто-то не прав".
Во-первых, в C++ контекстных кейвордов, как в том анекдоте (Сначала было мало. Пришли мы с женой module c import, стало вдвое больше). В частности, requires не контекстный keyword в этом легко убедиться, проверив компилируемость int requires; https://gcc.godbolt.org/z/b39cvz:


int final;      // OK
int override;   // OK
int module;     // OK
int import;     // OK
int requires;   // Fail

Во-вторых, requires-expression может использоваться где угодно, к примеру (https://gcc.godbolt.org/z/zHRSg5)


bool b = requires { 2 + 2; };

Возможно, вас смутило, то что это пока не работает в MSVC, но они об этом честно предупреждали, анонсируя свою поддержку концептов.

Конечно, работает.

Это не правда, requires не контекстный, и использовать requires-expression не обязательно внутри шаблонов.

И как это связано с coroutine frame?

Если вы сделаете member-function корутиной вы тоже ожидаете, что поля класса скопируются в coroutine frame?
Дискуссия о том, чтобы как-то улучшить статус-кво, как я понимаю заглохла: https://github.com/GorNishanov/coroutines-ts/issues/32

Почему не захватить this в capture-list лямбды? Тогда весь код внутри вышел бы чуть проще. Но так получилось, что, видимо, лямбда-корутины в компиляторе пока поддерживаются не полностью, поэтому такой код работать не будет.

Это типичная ошибка работы с корутинами: https://quuxplusone.github.io/blog/2019/07/10/ways-to-get-dangling-references-with-coroutines/#exciting-new-way-to-dangle-a-reference и нет, это не недоделка в компиляторе.

Добавлю к списку:


  • "Создание неявных виртуальных деструкторов для полиморфных типов"
    Плохая идея сама по себе, даже если бы не требовала слома ABI.
  • "возвращаемый тип у push_back может быть изменен, если сломать текущий ABI"
    Можно поменять и не ломая ABI, как это сделали в C++20 для std::list::remove.
  • "А вообще, действительно ли нам нужен и push_back, и emplace_back?"
    Объединить их можно было бы, но тут надо опять говорить об API а не ABI.

Разве понятие "implicitly creating objects" вошло в C++20? p0593 ведь отложили до C++23.

Обычно у объекта переведенного в пустое-но-валидное состояние потом вызывается деструктор. То есть для оптимизации компилятору нужно догадаться, что сумма 2-х действий: "зачистка" объекта (как правило, случающаяся внутри move constructor или move assignment) + вызов деструктора у "зачищенного" объекта это noop. Чтобы догадаться нужно много и интенсивно инлайнить, на практике такое далоко не всегда происходит.

Нет, в гцц он сравнивает указатели на массивы, в clang он сравнивает сами массивы.

Это и получится, если при обходе подобъектов не разобрать случай массивов, там уж как if-ы сложатся, декэим до указателей или идем перебирать элементы.


Загружал бы два байта сразу одной командой и сравнивал бы два байта сразу одной командой.

Вы говорите про ассемблер, очевидно, что в C++17 это не выразимо для ровно той структуры, что вы написали. Eсли быстродействие сравнения этих структур важно, есть много способов, как это написать.


struct S1 { char c[2]; };
struct S2 { array<char, 2> d; };
struct S3 { uint16_t e; };
struct S4 {  // возможно, в C++23
  struct layoutas(char[2]) {
    char a, b;
  };
};

Что же до примера с полем char a[32]; замените тип на array<char, 32> и будет то что вы хотите: https://godbolt.org/z/x9Kebq

Очевидно что в gcc, что в clang-е кодогенератор для defaulted operator == просто рекурсивно обходит подобъекты, я бы тоже так сделал в первом приближении. При этом ни там ни там случай массовов пока не рассмотрели отдельно. Вы завели issue? Уверен их быстро исправят. Что касается вашего первого примера с char a, b; то как бы вы написали его руками эффективнее?

Жаль, сейчас ни одна IDE этого не делает. Надо закинуть идею разработчикам.

https://youtrack.jetbrains.com/issue/RSCPP-24125 (пункт 1.3)

Спасибо за объяснение, кажется, что действительно во всех случаях компилятор может выполнить copy elision. Правда, остается проблема, что сейчас для каждого компилятора есть пример, когда он эту отпимизацию не выполняет. То есть в отличие от guaranteed RVO, который был просто стандартизацией существующей практики, уже реализованной во всех компиляторах, чтобы поддержать ваш proposal вендорам придется поработать.

Это не такой уж простой анализ. Я же правильно понимаю, что в этом (https://gcc.godbolt.org/z/fKFT6d) случае


X f() {
    if (false)
    {
        X b { "b" };
        return b;
    }
    X a { "a" };
    return a;
}

copy elision тоже гарантируется? А как насчет goto? (https://gcc.godbolt.org/z/HB09nk).


X f() {
    if (false)
    {
label:        
        X b { "b" };
        return b;
    }
    X a { "a" };
    goto label;
    return a;
}
Ваше предложение (P2025) кажется классным, но вы уверены в его реализуемости? Ведь это потребует некоторого control-flow анализа на фронтэнде, и, к примеру, gcc прямо сейчас с ним не справляется: gcc.godbolt.org/z/kMKQq5
Если вы знаете какие-то примеры ошибок вообще и с концептами в частности, сообщайте нам, пожалуйста, о них. Исправление красного кода для нас (ReSharper C++) приоритет номер один.

Information

Rating
Does not participate
Registered
Activity