cpp-ru / ideas

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

Починить семантический смысл auto для structured binding #386

Open Neargye opened 3 years ago

Neargye commented 3 years ago

Перенос предложения: голоса +0, -5 Автор идеи: Даниил Милютин

Текущая реализация structured binding (SB) не соответствует семантике auto. Хочется чтобы для SB работали обычные правила auto для переменных.

В общем случае хочется следующее

//I want
auto cv ref [x1, /*...,*/ xN] = s;
//to be equivalent to
auto cv ref x1 = std::get<0>(s);
//...
auto cv ref xN = std::get<N>(s);

Сейчас это не так. Рассмотрим примеры в коде. (Код примеров см. также здесь.)

void do_smth_with(int& i) { ++i; }
void do_smth_with(double& x) { x = x+1; }

void do_auto_with(std::tuple<int&, double&> t)
{
    auto [x, y] = t;
    do_smth_with(x);// referenced by "t[0]" changed. Do we want this?
    do_smth_with(y);// referenced by "t[1]" changed. Do we want this?
}

void do_auto_cref_with(std::tuple<int const&, double const&> t)
{
    auto [x, y] = t; // error: binding reference of type 'int&' to 'const int' discards qualifiers
    do_smth_with(x);
    do_smth_with(y);
}

void do_fixed_behavior_with(std::tuple<int&, double&> t)
{
    // I want auto [x,y] = t be this;
    auto x = std::get<0>(t); 
    auto y = std::get<1>(t);
    do_smth_with(x); //fine. changed temporary variable
    do_smth_with(y); //fine. changed temporary variable
    //referenced by tuple t did NOT change
}

void do_fixed_behavior_with(std::tuple<int const&, double const&> t)
{
    // I want auto [x,y] = t be this;
    auto x = std::get<0>(t); 
    auto y = std::get<1>(t);
    do_smth_with(x); //fine. changed temporary variable
    do_smth_with(y); //fine. changed temporary variable
    //referenced by tuple t did NOT change
}

Хочется, чтобы при использовании auto без ref-modifiers выводились не ссылочные типы, а значения.


Расскажу, как я на это наткнулся.

Решил я написать свой zip для коллекций. В итоге успешно взял код отсюда

Проблема была в том, что я использовал zip с постоянными коллекциями примерно так :

for(auto [x,y]: zip(vec_x, vec_y))
   do_smth_by_nonconst_ref(x); // error
// А ожидалось схожее с...
for(auto x: vec_x)
   do_smth_by_nonconst_ref(x); // ok

zip_helper::iterator по постоянным коллекциям при разименовании возващает tuple состоящий из const ссылок. Тип x,y выведен как постоянная ссылки. И причина как раз в том как работает SB. Для получения желаемой временной переменной писал следующий костыль (потом по-другому починил, но это другая история)

for(auto [x,y]: zip(vec_x, vec_y))
{
   auto X = x; // what a mess!!!
   do_smth_by_nonconst_ref(X); 
}

Получается, что в этом случае SB портят жизнь и увеличивают объём кода. И, как я уже объяснил выше, не соответствует семантике auto.

Neargye commented 3 years ago

amlet 11 апреля 2019, 7:46 5 минусов, и ни одного комментария... Приведённый пример конечно диковатый, но реально плюсы с каждым новым стандартом становятся всё больше противоречащими себе:

auto a = ... ; // копируется значение

auto & a = ... ; // а вот мы явно указываем на ссылочный тип

decltype(auto) a = ... ; // сохраняем тип для a выражения справа

и тут неожиданно:

auto [a, b] = ... ; // сохраняем типы исходя выражений справа, даже если там ссылки

Может реально как-то более одинаково похожие выражения вести себя должны? Может реально выражение:

decltype(auto) [a, b] = ... ;

auto & [a, b] = ... ;

были бы лучше?

apolukhin commented 3 years ago

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