6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
||||||
1 | ||||||
Как избежать дублирования кода при написании константного и не константного метода?28.02.2022, 15:43. Показов 2403. Ответов 36
Есть класс Buffer, который содержит метод forBounds, который в качестве параметров принимает вспомогательный класс Bounds и шаблонный элемент _Func, который должен быть лямбда-функцией, в которой описывается логика. В общем, сам метод чем-то напоминаем функцию std::for_each. Проблема заключается в том, что мне нужно как-то сделать два метода const и не const версию. Дублировать код и писать макросы как-то не хочется.
Есть ли способ, как можно сделать два одинаковых по коду метода, но так, чтобы один был const, а другой нет, но при этом избежать дублирования?
0
|
28.02.2022, 15:43 | |
Ответы с готовыми решениями:
36
Возврат константного значение из функции/метода Выполнение метода в зависимости от константного свойства Как избежать дублирования кода при использовании virtual функций? Избежать дублирования проверок при выполнении метода |
2327 / 1816 / 751
Регистрация: 27.07.2012
Сообщений: 5,357
|
||||||
28.02.2022, 16:03 | 2 | |||||
А в вашем случае можно просто из неконстантного метода вызвать константный как обычно.
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
|
28.02.2022, 16:20 [ТС] | 3 |
John Prick, если я из неконстантного метода вызываю константный, то происходит stack overflow, а если я сделаю std::as_const(*this).forBounds, то смысла от неконстантного метода нет, т.к. параметр типа _Func, который является лямбда функцией не сможет изменять состояния буффера.
0
|
2327 / 1816 / 751
Регистрация: 27.07.2012
Сообщений: 5,357
|
|
28.02.2022, 16:31 | 4 |
Это не из-за константности/неконстантности. Ищите ошибку в коде.
Добавлено через 6 минут Другое дело, что если у вас константный метод должен что-то изменять в объекте, то почему он тогда константный?
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
||||||
28.02.2022, 16:33 [ТС] | 5 | |||||
Есть неконстантный объект класса Buffer. Я для него вызываю метод forBounds, который имеет в себе след. строчку->
Добавлено через 1 минуту John Prick, константный метод не должен ничего изменять, он принимает лямбду. Если метод константный, то лямбда не сможет ничего изменить и будет ошибка.
0
|
2327 / 1816 / 751
Регистрация: 27.07.2012
Сообщений: 5,357
|
|
28.02.2022, 16:36 | 6 |
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
||||||
28.02.2022, 16:39 [ТС] | 7 | |||||
John Prick,
0
|
2327 / 1816 / 751
Регистрация: 27.07.2012
Сообщений: 5,357
|
|
28.02.2022, 16:51 | 8 |
Ну тут проблема в том, что в константном методе вызывается
at(i) , которая возвращает const int & , тогда как лямбда принимает int& для того, чтобы изменить его. Собственно, тут и возникает вопрос, зачем в константном методе изменять объект. Если это нужно, сделайте метод неконстантным, и всё.
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
|
28.02.2022, 17:01 [ТС] | 9 |
John Prick, метод at имеет конст и неконст перегрузки. Мне нужно, чтобы методом forBounds можно было пользоваться, как с целью изменения состояния буффера, так и способом частичного обхода коллекции без изменения состояния самого буффера. Я бы мог воспользоваться паттерном итератор, но, как по мне, это уже будет оверинженеринг. Неужели остается писать макрос под целый метод?
0
|
2327 / 1816 / 751
Регистрация: 27.07.2012
Сообщений: 5,357
|
|
28.02.2022, 17:16 | 10 |
Да, имеет. Но в const методе вызывается const версия at, так как тип this в таком методе - const Bounds * const.
Добавлено через 3 минуты А зачем вам в лямбде всё окружение передавать [&] , когда используется только bounds.getWidth()? Передайте это число либо параметром, либо [w = bounds.getWidth()]. Сложно же разбираться в таких связях будет.
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
|
28.02.2022, 17:23 [ТС] | 11 |
John Prick, я на это и рассчитывал. Например, я захочу обойти буффер в заданных границах, но не хочу изменять его состояние. Для этого бы, желательно, вызвать const версию forBounds. При вызове этого метода я не смогу изменить лямбдой состояния буффера - будет ошибка компиляции. Для случая, когда объект не const, мне нужен метод forBounds, который смог бы принять лямбу, которая сможет изменить состояние буффера. При дублировании кода все работает замечательно, но мне таааак не хочется этого делать... А макрос на целый метод уродство ужасное. Может, есть способ сбросить const спецификатор у метода? В гугле все предлагают кастовать this, но это не подходит.
Добавлено через 1 минуту для примера быстро накидал, даже не задумывался.
0
|
фрилансер
5826 / 5346 / 1097
Регистрация: 11.10.2019
Сообщений: 14,284
|
|
28.02.2022, 18:19 | 12 |
не советую такое использовать, можно такущие грабли отхватить То же самое касается mutable полей класса
Единственный случай, когда мне пришлось применить mutable - при наследовании виртуального метода в Qt. Метод был константный, и это поменять невозможно. Аким2020, а как метод может быть одинаковым и для константного объекта, и для не константного? Тут что-то одно может быть. Либо тело функции всё же должно быть разное в лямбду можно захватить неконстантный указатель на буфер - это будет решением.
0
|
2327 / 1816 / 751
Регистрация: 27.07.2012
Сообщений: 5,357
|
|
28.02.2022, 18:30 | 13 |
Да я не говорю, что так надо делать, просто так технически возможно. Но ТС говорит, что у него так тоже не работает.
А mutable вполне можно использовать для тех частей класса, которые при вызове константных методов должны изменяться, но при этом логическое состояние самого объекта не меняется. Например, блокировки при многопоточном доступе.
0
|
фрилансер
5826 / 5346 / 1097
Регистрация: 11.10.2019
Сообщений: 14,284
|
|
28.02.2022, 18:38 | 14 |
John Prick, вот именно из-за многопоточности и опасно mutable использовать. Если мутекс имеет два режима блокировки - только чтение или только запись, то во время readonly можно по невнимательности поменять значение mutable-поля. И привет
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
|
28.02.2022, 20:11 [ТС] | 15 |
Алексей1153,
тело самого метода одинаковое, как для конст, так и не конст. Тут проблема заключается в лямбде, которая для константного буффера не должна иметь возможность менять состояние объекта, а для не константного - нет. Вот я и не знаю, что делать... Можно, конечно, отдельной функцией реализовать и передавать буффер в качестве параметра, но мне хочется, чтоб это был метод класса.
0
|
фрилансер
5826 / 5346 / 1097
Регистрация: 11.10.2019
Сообщений: 14,284
|
||||||
28.02.2022, 21:04 | 16 | |||||
так в чём проблема то ? Захват будет с таким же квалификатором, как и захваченный объект
0
|
SmallEvil
|
28.02.2022, 21:10
#17
|
Не по теме: Алексей1153, список аргументов лямбды можно опускать ?
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
|
28.02.2022, 21:21 [ТС] | 18 |
Алексей1153, проблема в том, что я не хочу захватывать буффер лямбдой. Лямбда - это та функция, которая будет применена для каждого элемента коллекции текущего объекта. Проще понять на методе, который бы назывался forEachElement(const _Func& func). В таком виде(без спецификации const) лямбда сможет изменить каждый элемент. Теперь я хочу сделать такой же метод, но чтоб можно было обходить все элементы коллекции, но без возможности изменять элементы, поэтому добавляю к методу спецификацию const. Теперь у меня есть проблема дублирования кода. Внутренности двух методов абсолютно одинаковые, но вот лямбды должны быть разные. В случае const метода, принимаемая лямбда не должна иметь возможность менять элементы коллекции, а в не const - может менять. Вопрос, как мне избежать дублирования кода?
0
|
фрилансер
5826 / 5346 / 1097
Регистрация: 11.10.2019
Сообщений: 14,284
|
|
28.02.2022, 21:31 | 19 |
SmallEvil, можно, но в некоторых случаях всё равно необходимо оставлять скобки (например, при подсказке возвращаемого типа, при указании mutable или noexcept)
Аким2020, если речь о производительности, то захват у меня показан по ссылке, а не по значению. насчёт константности - можно принудительно передать константную ссылку или указатель, если это нужно
0
|
6 / 5 / 1
Регистрация: 05.10.2020
Сообщений: 122
|
||||||||||||||||
28.02.2022, 23:29 [ТС] | 20 | |||||||||||||||
В общем, я ничего лучше не придумал, чем сделать макрос, который выглядит так:
0
|
28.02.2022, 23:29 | |
28.02.2022, 23:29 | |
Помогаю со студенческими работами здесь
20
Как избежать дублирования кода? Как избежать дублирования кода в Си Как избежать дублирования кода? Наследование Ошибка при выводе константного значения С++ Ошибка при обращении к методу константного объекта Усечение константного значения при присвоении значений объектам структуры Избежать дублирования кода Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |