EdgeAligned 83 16 ноября, 2023 Опубликовано 16 ноября, 2023 (изменено) · Жалоба namespace N1{ namespace N2 { void Foo() { cout << "Ф-ция из N1::N2" << endl; } } } void Foo() { cout << "Ф-ция без простр.имен" << endl; } int main() { Foo(); N1::N2::Foo(); Ф-ция без простр.имен Ф-ция из N1::N2 У static совершенно определённая цель, и он не имеет отношения к пространству имен А здесь - просто функции без привязки к классам, уровень обычного Си с добавлением namespace. И самое главное, это - НЕ безымянное пространство имён. Оно очень даже имянное. Безымянное - это просто :: Изменено 16 ноября, 2023 пользователем EdgeAligned Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 176 16 ноября, 2023 Опубликовано 16 ноября, 2023 · Жалоба 1 час назад, EdgeAligned сказал: У static совершенно определённая цель, и он не имеет отношения к пространству имен Еще как имеет. Более того, в C++11 (вроде) хотели вовсе уйти от static, а потом вернули. Но Ваш пример совсем не про то, о чем я спрашивал🙂 То, что Вы показали, мне известно. Вот это логично вызовет ошибку: namespace { void func() {} } void func() {} int main() { func(); // error: call to 'func' is ambiguous } Вопрос в том, существует ли какая-то возможность поломать следующий код: namespace { void func() {} } int main() { func(); // и каким-то образом вызовется не func() выше, а func() из другой единицы трансляции } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 83 16 ноября, 2023 Опубликовано 16 ноября, 2023 · Жалоба Static относится к типу хранения в классах. Static-метод доступен без создания объекта класса. А в старом сишном понимании static-функция ограничивается видимость только внутри одного файла. Про безымянное пространство имён уже написал. У вас оно очень даже именованное. Если напишите при вызове ::Foo(), то вызовется функция вне пространства имён, из глобального пространства Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 176 16 ноября, 2023 Опубликовано 16 ноября, 2023 · Жалоба 4 минуты назад, EdgeAligned сказал: У вас оно очень даже именованное. Где? Я не про nsDriver говорю же. А про доступ к функциям из неименованного пространства. 4 минуты назад, EdgeAligned сказал: А в старом сишном понимании static-функция ограничивается видимость только внутри одного файла. Именно, что ограничивают область видимости. Поэтому все что будет находиться внутри неименованного пространства тоже будет иметь свойства как у static. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 83 16 ноября, 2023 Опубликовано 16 ноября, 2023 · Жалоба Так оное выполняется как и в обычном Си. То есть, с глобальном пространстве имён (без имени) может существовать только одна функция, два одинаковых прототипа недопустимы. Но если напишите Foo() и Foo(int a), то получите перегрузку функций. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 176 16 ноября, 2023 Опубликовано 16 ноября, 2023 · Жалоба 8 часов назад, EdgeAligned сказал: Так оное выполняется как и в обычном Си. То есть, с глобальном пространстве имён (без имени) может существовать только одна функция, два одинаковых прототипа недопустимы. Но если напишите Foo() и Foo(int a), то получите перегрузку функций. Это тоже все понятно. Речь конкретно про безымянные пространства. В случае именованных я могу в другой единице трансляции объявить переменные/функции, которые в текущей единице трансляции вызовут ошибку компиляции, если они уже объявлены в этом пространстве: A.cpp namespace A { void func() {} } B.cpp namespace A { void func() {} } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 16 ноября, 2023 Опубликовано 16 ноября, 2023 · Жалоба 3 часа назад, EdgeAligned сказал: А в старом сишном понимании static-функция ограничивается видимость только внутри одного файла. И безымянное пространство имен тоже. 3 часа назад, EdgeAligned сказал: Про безымянное пространство имён уже написал. У вас оно очень даже именованное. И какое у него имя? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 83 16 ноября, 2023 Опубликовано 16 ноября, 2023 · Жалоба Я имел ввиду то, что писал автор вот тут: namespace nsDriver { namespace nsHw { А про анонимное пространство имен - у него тоже есть хоть не имя, но способ обращения к нему через :: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 176 16 января Опубликовано 16 января · Жалоба Как по феншую в C++ сделать такой трюк? Нужно заиметь хоть трижды перегруженную, хитронаписанную, но корректно работающую конструкцию, которая: 1) имеет одно и то же имя upd_bit(); 2) имеет 2 или 3 управляющих аргумента; если их 3, то третий по желанию может быть опущен в точке вызова; 3) управляющие аргументы, в зависимости от порядка следования, совершают действия над основным операндом в порядке чтения "слева-направо". Поясню. Сейчас у меня давным давно написан весьма хитрый Си макрос, которым очень просто пользоваться. Вот такая запись (обратите внимание на порядок следования суб-макросов rst(), set(), inv()) сначала сбросит MCU->REG по маске R_MSK, и лишь только потом установит биты S_MSK, но в рамках одиночной операции чтения-модификации-записи. Битовая маска инверсии не используется (0). upd_bit(MCU->REG, rst(R_MSK), set(S_MSK), inv(0)); Если бы нужно было акцентировать внимание сначала на установке битов, затем на сбросе, то так и записывали бы upd_bit(MCU->REG, set(S_MSK), rst(R_MSK), inv(0)); Такое удобно, когда в одном регистре в разные биты надо записать разные значения, по ходу чтения даташита (чтобы еще было читаемо все). И еще удобнее (первой записью) обновлять значения в группе полей одного регистра за раз (сначала их чистить, потом устанавливать во что нужно). Весьма сложная для понимания макросная кухня Си, для упрощения поста, не приводится (при желании - могу показать), однако лично мне не удалось решить проблему с "плавающим" третьим аргументом. Про вариативные макросы я, разумеется, в курсе, но upd_bit() - это хитро разворачиваемый макрос, которому не получается указать __VA_ARGS__. А в коде вариант, где inv(0) вообще не требуется, самый распространенный. И этот аргумент сорит перед глазами. Имеет ли смысл такое реализовать в виде C++ функтора, у которого будет два перегруженных operator() (с 3 и 4 аргументами, соответственно), а в классе этого функтора создать публичные вспомогательные методы set(), rst(), inv() и вызывать у аргументов? Но не представляю, как так безымянно вызывать эти самые set(), rst() и т.д.? Т.е. не ясно, как (где?) определить некие вспомогательные set(), rst() и т.д., чтобы они не лезли в пространство имен, и жили только, условно, внутри скобок вызова () этого самого upd_bit(). Т.е. надо как-то создать класс, в котором будут находиться определения этих set(), rst(), inv(), они не видны за пределами класса, и их можно вызывать контекстно для функтора - но может ли так C++? class upd_bit { auto set(auto s) {...} auto rst(auto r) {...} auto inv(auto i) {...} auto operator()(auto reg, ?, ?) {...} auto operator()(auto reg, ?, ?, ?) {...} }; Но как бы так вызывать, чтобы в списке аргументов символы 'set' распознавались как члены класса upd_bit??? Чтобы вызывать по красоте upd_bit(MCU->REG, rst(R_MSK), set(S_MSK)); а не криво upd_bit(MCU->REG, upd_bit.rst(R_MSK), upd_bit.set(S_MSK)); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 83 16 января Опубликовано 16 января (изменено) · Жалоба Вообще-то, в макросе MODIFY_REG(), который в CMSIS, происходит сначала чтение целевого регистра, затем применение к нему масок сброса и установки, затем измененное значение записывается целиком в целевой регистр. И в отношении регистров периферии навряд ли нужна необходимость разного порядка операций сброса и установки. И я не думаю, что имеет большой смысл изобретать еще одну такую же сущность, как MODIFY_REG(). А понятие инверсии битов в этой конструкции на практике можно применить разве что выходным пинам. И сделать это можно при помощи перегрузки шаблона. То есть функция с шаблоном template<bool inv> и та же самая функция без этого шаблона. Так же, применительно к выходным пинам, сброс-установку по раздельным маскам можно (и нужно) делать через BSRR, и там так же не имеет значения порядок операций. При перегрузке функций не имеет значения порядок следования имен параметров функции, если они одинаковых типов. То есть (int a, int b) и (int b, int a) - это одно и то же и будет выдана ошибка. А вот (int a, char b) и (char b, int a) - это уже различие и функция может быть перегружена. И кстати. Если пишите слово class, то все методы, написанные без предшествующего слова public: будут закрытыми членами класса и к ним не будет доступа извне. И именно при помощи private: можно убрать из области видимости закрытые (приватные) методы класса. Переменное число аргументов функции, если не ошибаюсь, работает по-сишному, то есть ужасно. Переменное число аргументов шаблона фунции работает лучше, но недопилено и фактически так же ужасно, хоть и чутка лучше. Ну и указание auto для метода, который в принципе ничего не возвращает - это лишнее запутывание. А, ну и конечно, еще написать static перед всеми методами, чтобы можно было бы вызывать без объекта, как фукнцию через имя_класса::имя_функции(); Изменено 17 января пользователем EdgeAligned Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 176 17 января Опубликовано 17 января · Жалоба Это все мне известно, вопрос касался сохранения конкретно указанного синтаксиса. А имя_класса::имя_функции() - уже громоздкий костыль в таком случае как минимум. Насчет auto - во-первых, это некомпилируемый логический пример, во-вторых, методы возвращают тот же тип, что имеют аргументы. Насчет инверсии - в некоторых USB-регистрах надо и устанавливать, и сбрасывать, и инвертировать биты одной операцией RMW. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 17 января Опубликовано 17 января · Жалоба 10 hours ago, Arlleex said: Как по феншую в C++ сделать такой трюк? Можно придумать, как по-феншую сделать трюк типа `upd_bit(MY_REG).set(SET_MSK).clr(CLR.MSK)`. А ваша задача в исходном звучании не решается, имхо. Надо эти set() / clr() в общую область видимости выносить. Можете обернуть всё это в `namespace HwRegsWrapper { ... };` и в своих драйверах дописать `using namespace HwRegWrapper;`, тогда в остальных местах эти имена не будут мешаться. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 17 января Опубликовано 17 января · Жалоба 11 часов назад, Arlleex сказал: Как по феншую в C++ сделать такой трюк? ... Вот такая запись (обратите внимание на порядок следования суб-макросов rst(), set(), inv()) сначала сбросит MCU->REG по маске R_MSK, и лишь только потом установит биты S_MSK, но в рамках одиночной операции чтения-модификации-записи. Битовая маска инверсии не используется (0). upd_bit(MCU->REG, rst(R_MSK), set(S_MSK), inv(0)); Если я правильно понял задачу, то это можно сделать примерно так: struct Set { Set(uint32_t mask) : m_mask(mask) { } void apply(volatile uint32_t& reg) { reg |= m_mask;} private: uint32_t m_mask; }; struct Clr { Clr(uint32_t mask) : m_mask(mask) { } void apply(volatile uint32_t& reg) { reg &= ~m_mask;} private: uint32_t m_mask; }; struct Inv { Inv(uint32_t mask) : m_mask(mask) { } void apply(volatile uint32_t& reg) { reg ^= m_mask;} private: uint32_t m_mask; }; template <typename ... Operations> void modifyReg(volatile uint32_t& reg, Operations&& ... ops) { (..., void(ops.apply(reg))); } int main() { uint32_t reg {0b10001}; modifyReg(reg, Set(0b010), Clr(0b01)); std::cout << std::hex << reg << "\r\n"; modifyReg(reg, Inv(0b1111)); std::cout << std::hex << reg << "\r\n"; } 2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Edit2007 3 17 января Опубликовано 17 января · Жалоба сделать две функци, без разницы где писать порядок действий, в названии или в параметрах upd_SetClr(reg, mask) { Set(reg, mask); Clr(reg, mask); } upd_ClrSet(reg, mask) { Clr(reg, mask); Set(reg, mask); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 17 января Опубликовано 17 января · Жалоба 1 час назад, AHTOXA сказал: Если я правильно понял задачу, то это можно сделать примерно так: Если нужно, чтобы это всё реализовывалось за одну RMW операцию с регистром, то делаем через вспомогательную переменную, и убираем volatile в параметрах функций apply(): template <typename ... Operations> void modifyReg(volatile uint32_t& reg, Operations&& ... ops) { auto val = reg; (..., (void)ops.apply(val)); reg = val; } вот ссылка на wandbox, поиграться. UPD: вот ещё ссылка, немножко подрихтовал: wandbox 2 2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться