cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
90 stars 0 forks source link

piecewise_construct для кортежей #223

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +9, -0 Автор идеи: Sergey K

Хотелось бы сконструировать кортеж, элементы которого не copy-constructible, не move-constructible и не имеют конструктора с одним аргументом или конструктора по умолчанию.

У пары (std::pair) есть конструктор для поэлементного конструирования. Первым аргументом он принимает плейсхолдер std::piecewise_construct, а двумя последующими аргументами - кортежи из любого количества элементов. Каждый кортеж разбирается на элементы, которые передаются в конструктор соответствующего элемента пары как список аргументов (ожидается, что элемент пары имеет соответствующий конструктор). Кортеж является естественным обобщением пары, поэтому хотелось бы видеть такой конструктор и для кортежей.

Пример:

struct Foo {
    Foo(const Foo&) = delete;
    Foo(Foo&&) = delete;
    Foo& operator=(const Foo&) = delete;
    Foo& operator=(Foo&&) = delete;
    /* Единственный способ создания структуры -
     * конструктор с более чем одним аргументом.
     */
    Foo(int, float) {}
};

int main()
{
    int a = 1;
    float b = 3.14f;
    std::pair<Foo, Foo> fooPair(std::piecewise_construct, std::tie(a, b), std::tie(a, b)); // ОК
    std::tuple<Foo> fooTuple(std::piecewise_construct, std::tie(a, b)); // Ошибка - нет такого конструктора у кортежа
}

Ещё один возможный вариант использования - создание кортежа с раскрытием списка шаблонных параметров, которое делается через раскрытие sizeof и оператора "запятая":

https://stackoverflow.com/questions/22560100/how-to-initialize-all-tuple-elements-by-the-same-arguments

template <typename... TElements>
struct Container {
    // Некорректный код из ответа на SO. Нет такого конструктора.
    Container(Foo foo, Bar bar)
        : tuple(std::piecewise_construct, (sizeof(TElements), std::tie(foo, bar))...)
    {}
    std::tuple<TElements...> tuple;
};
apolukhin commented 3 years ago

Andrey Davydov, 29 сентября 2017, 11:56 А как Вы себе представляете сигнатуру такого конструктора? Его template headers должна же будет содержать переменное число template parameter packs, как это можно выразить на C++?

Дмитрий, 2 октября 2017, 16:08 Andrey Davydov, на самом деле, ничего сложного: https://wandbox.org/permlink/7RrDix2YhNoRCpSx (пример схематичный).

Andrey Davydov, 2 октября 2017, 17:02 dmitriy@izvolov.ru, Ваша реализация делает не то же, что piecewise_construct конструктор std::pair. Вы в конструкторе ::tuple создаете элементы std::tuple и передаете их в конструктор std::tuple, т.е. это не будет работать с noncopyable & nonmovable типами.

Дмитрий, 2 октября 2017, 17:13 Andrey Davydov, я просто показал принцип, который заключается всего-навсего в том, чтобы в поэлементном конструкторе принимать набор кортежей. Их дальше можно проверить на совпадение с классом std::tuple через концепты или SFINAE, а дальше они разворачиваются и бросаются в конструкторы конкретных элементов.

Пример, как я и написал, схематичный. Я же не буду реализовывать полноценный кортеж ради такого простого примера.