cpp-ru / ideas

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

Возможность явно указать квалификатор метода в момент вызова. #291

Closed apolukhin closed 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +1, -4 Автор идеи: A

Не редко декларация класса содержит одноименные методы с одинаковой сигнатурой, но с разными квалификаторами. При этом реализация const методов, обычно, является более легковесной. Решение - дублировать вызов константных методов с помощью неконстантных (например, begin () const и end () const дублировать сbegin () const и сend () const) - не выглядит красивым.

Вероятно, лучшим вариантом была бы возможность явно указать квалификатор вызываемого метода.

struct A
{
    void method ();
    void method () const;
};

void foo ()
{
    A value;

    // использовать
    value.const method();

    // вместо
    const A & alias;
    alias.method();

    // или вместо
    alias.сmethod();
}

Выше преставлен упрощенный пример. Например, если использовать доступ к методам через элементы контейнера или умный указатель, или пользовательский тип, реализующий оператор ->, то можно было бы писать так:

::std::shared_ptr< A > pointer = ::std::make_shared< A >();
pointer->const method();

Подобная семантика похожа, например, на явное указание template при вызове шаблонного метода

struct A
{
    template < typename _Type >
    void method ();
}

template < typename _T >
void foo ()
{
    A value;
    value.template method< _T >();
}
apolukhin commented 3 years ago

Andrey Davydov, 3 апреля 2018, 18:56 В С++17 добавили функцию as_const с помощью которой Ваш пример с alias станет покороче. К тому же получается консистентно с выбором перегрузки с нужным ref-qualifier:

std::move(value).method()     // для выбора method() &&
std::as_const(value).method() // для выбора method() const &

Явное указание template нужно только в dependent коде для правильного парсинга, но не для выбора нужной перегрузки функции.

A, 3 апреля 2018, 21:19 Andrey Davydov, такой подход как ::std::as_const я использую давно и нахожу его неудобным и плохо читаемым.

Вот такой пример, предположим неконстантные методы создают экземпляр объекта на который возвращается указатель, если он еще не создан.

using namespace std;

struct A
{
    void method ();
    void method () const;
};

struct B
{
    A * getA ();
    A * getA () const;
};

struct C
{
    B * getB ();
    B * getB () const;
};

void foo ()
{
    C c;

    // с использованием as_const
    as_const( *as_const( *as_const( c ).getB() ).getA() ).method();

    // с указанием квалификатора
    c.const getB()->const getA()->const method();
}

Использование as_const добавляет код слева и трудно сказать к чему он относится, когда указание const в месте вызова метода интуитивно понятно.

Насчет template - это был пример схожей семантики, но не способа применения.

A, 3 апреля 2018, 21:33 Обновлено 3 апреля 2018, 21:19

Andrey Davydov, не понял контекст применения

std::move(value).method()     // для выбора method() &&

Andrey Davydov, 3 апреля 2018, 21:42 stepsoft, а почему в Вашем примере константные методы возвращат неконстантные указатели?

Andrey Davydov, 3 апреля 2018, 21:48 stepsoft,

не понял контекст применения

struct X { ... };

struct Y {
  X &        x() &;       // #1
  X const &  x() const &; // #2
  X &&       x() &&;      // #3
};

void test(Y y) {
  y               .x(); // #1
  std::as_const(y).x(); // #2
  std::move(y)    .x(); // #3
}

A, 3 апреля 2018, 21:58 Andrey Davydov, такое бывает и не редко, например

Не всегда константный метод должен возвращать константный тип. И можно в примере указатель заменить на сам тип.

using namespace std;

struct A
{
    void method ();
    void method () const;
};

struct B
{
    A getA ();
    A getA () const;
};

struct C
{
    B getB ();
    B getB () const;
};

void foo ()
{
    C c;

    // с использованием as_const
    as_const( as_const( as_const( c ).getB() ).getA() ).method();

    // с указанием квалификатора
    c.const getB().const getA().const method();
}

A, 3 апреля 2018, 22:07 Andrey Davydov, Использование разных видов ссылок и применение квалификаторов (mutable, const, volatile) - это взаимодополняющие вещи. Применение одного не исключает применение другого.

languagelawyer, 23 мая 2018, 6:42 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1992/WG21%201992/X3J16_92-0136%20WG21_N0212.pdf

apolukhin commented 3 years ago

std::as_const в С++17 вырос как раз из обсуждения похожей идеи. Чтобы воскресить обсуждение решения данной проблемы на уровне языка надо найти кейс, который не покрывается std::as_const и std::move и не имеет решения через библиотекчные методы.