Перейти к содержанию
    

Плавный переход C -> C++ под МК

namespace N1{
namespace N2 {
void Foo()
{
	cout << "Ф-ция из N1::N2" << endl;
}
}
}
void Foo()
{
	cout << "Ф-ция без простр.имен" << endl;
}
int main()
{
	Foo();
	N1::N2::Foo();

Ф-ция без простр.имен
Ф-ция из N1::N2

У static совершенно определённая цель, и он не имеет отношения к пространству имен

А здесь - просто функции без привязки к классам, уровень обычного Си с добавлением namespace. И самое главное, это - НЕ безымянное пространство имён. Оно очень даже имянное. Безымянное - это просто ::

Изменено пользователем EdgeAligned

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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() из другой единицы трансляции
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Static относится к типу хранения в классах. Static-метод доступен без создания объекта класса. А в старом сишном понимании static-функция ограничивается видимость только внутри одного файла. 

Про безымянное пространство имён уже написал. У вас оно очень даже именованное.

Если напишите при вызове ::Foo(), то вызовется функция вне пространства имён, из глобального пространства 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, EdgeAligned сказал:

У вас оно очень даже именованное.

Где? Я не про nsDriver говорю же. А про доступ к функциям из неименованного пространства.
 

4 минуты назад, EdgeAligned сказал:

А в старом сишном понимании static-функция ограничивается видимость только внутри одного файла.

Именно, что ограничивают область видимости. Поэтому все что будет находиться внутри неименованного пространства тоже будет иметь свойства как у static.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так оное выполняется как и в обычном Си. То есть, с глобальном пространстве имён (без имени) может существовать только одна функция, два одинаковых прототипа недопустимы.

Но если напишите Foo() и Foo(int a), то получите перегрузку функций. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 часов назад, EdgeAligned сказал:

Так оное выполняется как и в обычном Си. То есть, с глобальном пространстве имён (без имени) может существовать только одна функция, два одинаковых прототипа недопустимы.

Но если напишите Foo() и Foo(int a), то получите перегрузку функций. 

Это тоже все понятно. Речь конкретно про безымянные пространства.

В случае именованных я могу в другой единице трансляции объявить переменные/функции, которые в текущей единице трансляции вызовут ошибку компиляции, если они уже объявлены в этом пространстве:

A.cpp

namespace A {
  void func() {}
}

B.cpp

namespace A {
  void func() {}
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, EdgeAligned сказал:

А в старом сишном понимании static-функция ограничивается видимость только внутри одного файла. 

И безымянное пространство имен тоже.

3 часа назад, EdgeAligned сказал:

Про безымянное пространство имён уже написал. У вас оно очень даже именованное.

И какое у него имя?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я имел ввиду то, что писал автор вот тут: 

namespace nsDriver {
  namespace nsHw {

А про анонимное пространство имен - у него тоже есть хоть не имя, но способ обращения к нему через ::

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как по феншую в 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));

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще-то, в макросе 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 перед всеми методами, чтобы можно было бы вызывать без объекта, как фукнцию через имя_класса::имя_функции();

Изменено пользователем EdgeAligned

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это все мне известно, вопрос касался сохранения конкретно указанного синтаксиса.

А имя_класса::имя_функции() - уже громоздкий костыль в таком случае как минимум.

Насчет auto - во-первых, это некомпилируемый логический пример, во-вторых, методы возвращают тот же тип, что имеют аргументы.

Насчет инверсии - в некоторых USB-регистрах надо и устанавливать, и сбрасывать, и инвертировать биты одной операцией RMW.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 hours ago, Arlleex said:

Как по феншую в C++ сделать такой трюк?

Можно придумать, как по-феншую сделать трюк типа `upd_bit(MY_REG).set(SET_MSK).clr(CLR.MSK)`.

А ваша задача в исходном звучании не решается, имхо. Надо эти set() / clr() в общую область видимости выносить.

 

Можете обернуть всё это в `namespace HwRegsWrapper { ... };` и в своих драйверах дописать `using namespace HwRegWrapper;`, тогда в остальных местах эти имена не будут мешаться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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";
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

сделать две функци, без разницы где писать порядок действий, в названии или в параметрах
 

upd_SetClr(reg, mask) 
 { Set(reg, mask); Clr(reg, mask);
  }

upd_ClrSet(reg, mask) 
{ Clr(reg, mask); Set(reg, mask);
 }

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...