Предотвращение вызова константной функции для неконстантного объекта - PullRequest
5 голосов
/ 14 мая 2019

Следующий код содержит как постоянную, так и неконстантную версию operator(). Он выводит

Неконстантный оператор, ложь
Постоянный оператор, истина
Постоянный оператор, истина
Постоянный оператор, истина

Т.е. версия const вызывается, если либо объект типа S является const, либо если переданный указатель является const - lines // 2, // 3, // 4.Теперь я хочу, чтобы код в строке // 2 приводил к ошибке времени компиляции, т.е. я хочу, чтобы const-версия могла вызываться только для const-объектов.Очевидно, что static_assert на is_const_v<decltype(*this)> не будет работать.Любые другие идеи?
Я знаю, легко преобразовать неконстантную переменную в константную.Но это сделало бы неправильное использование как минимум очевидным.

#include <iostream>
#include <type_traits>

struct S
{
    void
    operator()( int * )
    {
        std::cout << std::boolalpha
            << "Non-const op, "
            << std::is_const_v<typename std::remove_reference_t<decltype(*this)> > << '\n';
    }
    void
    operator()( int const * ) const
    {
        std::cout << std::boolalpha
            << "Const op, "
            << std::is_const_v<typename std::remove_reference_t<decltype(*this)> > << '\n';
    }
};

int main()
{
    S         s1;
    S const   s2;
    int       i1= 0;
    int const i2= 1;

    s1( &i1 ); // 1
    s1( &i2 ); // 2
    s2( &i1 ); // 3
    s2( &i2 ); // 4
}

Редактировать
Мое объяснение заключается в следующем.Я храню отправленный указатель.Это требует отбрасывания константности представленного указателя.Теперь я хочу предотвратить ошибочное изменение данных const.

Ответы [ 3 ]

7 голосов
/ 14 мая 2019

Вы можете явно удалить следующую версию

void operator()( int const * ) = delete;

, чтобы запретить

s1( &i2 ); // 2

и

void operator()( int * ) const = delete;

, чтобы запретить

s2( &i1 ); // 3
2 голосов
/ 14 мая 2019

Давайте посмотрим, как это будет работать, если это будет не функция-член, если мы сделаем this явным параметром (мнимый синтаксис):

void call(S* this, int*) {
    // Wha? we clearly know `S*` is not const
    std::is_const_v<typename std::remove_reference_t<decltype(*this)> >
}

void call(S const* this, int const*) {
    // same
    std::is_const_v<typename std::remove_reference_t<decltype(*this)> >
}

Решением будет удаление функций с различным постоянством между параметрами:

void call(S* this, int*) {}
void call(S const* this, int const*) {}
void call(S* this, int const*) = delete;
void call(S const* this, int*) = delete;

Теперь то же самое можно сделать с помощью функции-члена:

struct S {
    void operator()(int*) {}
    void operator()(int const*) const {}
    void operator()(int const*) = delete;
    void operator()(int*) const = delete;
};
1 голос
/ 14 мая 2019

Вы можете предотвратить вызов функции, удалив версию, которая принимает const int*.Например:

#include <iostream>

struct S {
    void foo(int*) {
        std::cout << "Calling foo(int*)\n"; 
    }
    void foo(int const*) const {
        std::cout << "Calling foo(int const*)\n"; 
    }
    void foo(int const*) = delete; 
};

int main() {
    S s1;
    S const s2;
    int i1;
    int const i2;

    s1.foo(&i1); // This compiles fine (both mutable)
    s2.foo(&i2); // This compiles fine too (both const)
    s2.foo(&i1); // This also compiles (s2 const, i1 mutable)

    s1.foo(&i2); // This fails as intended (s1 mutable, i2 const)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...