Jump to content

    
ViKo

Нетиповой вариативный шаблон класса. Помогите написать.

Recommended Posts

48 минут назад, AHTOXA сказал:

переупаковывать в любом случае придётся. Скажем, если подцепить 8-битный дисплей на произвольные ноги порта.

В этом случае - да. И то, не на 100% обязательно. Можно перекодировать команды и данные под имеющуюся шину. constexpr функцией, например, если не вручную.
А если нужно управлять четырьмя выборами устройств, то и совсем не надо. Подать 0x0003 или 0x1080 - одинаково. 

Share this post


Link to post
Share on other sites

Не могу скомпилировать первый набросок. Где-то ошибся, но не пойму, где. Правильно ли я пытаюсь передать в шаблон ссылки на структуры constexpr?

Обновил вопрос. Тестовый пример проверяю здесь:

https://www.onlinegdb.com/fork/BJA5GHO3N

Как передать в конструктор шаблона нетиповой параметр - ссылку?

Если конструктор внутри определения класса, тогда компилируется нормально. Как только снаружи - затык.

#include <iostream>
#include <cstdlib>
#include <cstdint>
#include <cstddef>

struct Test_st { char Let; int Num; };

/*_____________________________________________________________________________*/
constexpr Test_st St1 = { 'A', 10 };
constexpr Test_st St2 = { 'B', 11 };

volatile int Temp1 {1};

template <const Test_st &S00, const Test_st &S01>
class Test_cl
{
	
public:
	Test_cl();
	
};

template <const Test_st &S00, const Test_st &S01>
class Test_cl<S00, S01>::Test_cl()
{
    { Temp1 = S00.Let << 8 | S01.Let; }
}


/*_____________________________________________________________________________*/
int32_t main(void)
{
    std::cout << Temp1 << '\n'; 
	Test_cl <St1, St2> Ti;
    std::cout << Temp1 << '\n';
}

 

Share this post


Link to post
Share on other sites

Вот показываю работающий вариант.

#include <iostream>
#include <cstdlib>
#include <cstdint>
#include <cstddef>

struct Test_st { char Let; int Num; };

/*_____________________________________________________________________________*/
constexpr Test_st St1 = { 'A', 10 };
constexpr Test_st St2 = { 'B', 11 };

volatile int Temp1 {1};

template <const Test_st &S00, const Test_st &S01>
class Test_cl
{
	
public:
	Test_cl()
    { Temp1 = S00.Let << 8 | S01.Let; }

};


/*_____________________________________________________________________________*/
int32_t main(void)
{
    std::cout << Temp1 << '\n'; 
	Test_cl <St1, St2> Ti;
    std::cout << Temp1 << '\n';
}

 

Share this post


Link to post
Share on other sites

Нашёл ошибку. Слово "class" в определении функции было лишним. Сколько, однако, мелочей нужно контролировать. Продолжу дальше в Кейле для класса порта.

Share this post


Link to post
Share on other sites
// это у нас будут типа регистры портов. 
static PortStruct portA { 0, 0 };
static PortStruct portB { 0, 0 };

// шаблонный класс порта. Параметр шаблона - буква порта (для проверки идеи этого достаточно)
template <char portLetter = 'A'>
class Port
{
public:
	// выдать указатель на регистры порта.
	static constexpr volatile PortStruct* getPortStruct() {
		if (portLetter == 'A')
			return reinterpret_cast<volatile PortStruct*>(&portA);
		return reinterpret_cast<volatile PortStruct*>(&portB);
	}

Возвращаюсь к этому коду. 

Поломалось сообщение. В общем, у меня было так, как ниже показал. Создавал объект Port, использовал его функции.

/*  Define GPIO structure pointer  */
	GPIO_TypeDef * GPIO =
		P00.gpio == 'A' ? GPIOA : P00.gpio == 'B' ? GPIOB :
		P00.gpio == 'C' ? GPIOC : P00.gpio == 'D' ? GPIOD :
		P00.gpio == 'E' ? GPIOE : GPIOH;

Если же использовать функции псевдонима, функции должны быть статическими. [ Здесь не соображу, как одна статическая функция работает с разными портами? ]
И указатель на GPIO должен выглядеть static constexpr GPIO_TypeDef * GPIO. Попытался так:
 

static constexpr GPIO_TypeDef * GPIO = reinterpret_cast<const GPIO_TypeDef *>
		(P00.gpio == 'A' ? GPIOA : P00.gpio == 'B' ? GPIOB :
		P00.gpio == 'C' ? GPIOC : P00.gpio == 'D' ? GPIOD :
		P00.gpio == 'E' ? GPIOE : GPIOH);

Получаю:
error: cannot initialize a variable of type 'GPIO_TypeDef *const' with an rvalue of type 'const GPIO_TypeDef *'

Видимо, нужно писать функцию, как в показанном выше фрагменте. Почему и зачем?

Share this post


Link to post
Share on other sites
12 часов назад, ViKo сказал:

Здесь не соображу, как одна статическая функция работает с разными портами?

С этим прояснилось. По шаблону ведь создаются разные классы. И в каждом свои статические функции, общие для всех объектов каждого класса. Но самих объектов или совсем нет, или по одному на класс.

Share this post


Link to post
Share on other sites

Вопрос конкретизирую.

	static constexpr volatile GPIO_TypeDef * GPIO { reinterpret_cast<volatile GPIO_TypeDef *>(GPIOA) }; 

	static constexpr volatile GPIO_TypeDef * getGPIO() {
		if (P00.gpio == 'A')
			return reinterpret_cast<volatile GPIO_TypeDef *>(GPIOA);
	}

Почему в шаблоне задать указатель (первое) не получается, а функцию, возвращающую указатель (второе) - получается?

Share this post


Link to post
Share on other sites

Здесь разница в том, что для переменной constexpr -- это обязательное требование, а для функции - это лишь пожелание.

То есть, у нас функция getGPIO(), несмотря на то, что перед ней написано constexpr, в действительности не является constexpr.

Я помню, что разбирался с этим, но точных формулировок уже не помню. Вроде бы, reinterpret_cast несовместим с constexpr.

 

 

Share this post


Link to post
Share on other sites

 

On 12/19/2019 at 6:19 PM, ViKo said:

Почему в шаблоне задать указатель (первое) не получается, а функцию, возвращающую указатель (второе) - получается?

GPIOA это reinterpret_cast<GPIO_TypeDef *> (GPIOA_BASE), а reinterpret_cast в параметрах шаблона использовать нельзя.

Edited by artkam

Share this post


Link to post
Share on other sites

Спрошу здесь, хоть и не по теме. Читаю книгу Вандервуда про шаблоны. Захотел проверить, как шаблон переменных работает (раздел 5.6 книги).
Не работает в онлайн-отладчиках следующий исходник. Компилятор C++17 задаю, хотя в книге сказано, начиная с C++14. В чем дело?

#include <stdint.h>
#include <iostream>

template<typename Т>
constexpr Т pi {3.1415926535897932385};

int main(void)
{
	using namespace std;

    std::cout << pi<double> << '\n';
    std::cout << pi<float> << '\n';
}

Отбой! Здесь, похоже 'T' была кириллицей написана. Копировал из книги, а там много символов неправильно определяется.

Однако, подложена свинка.

По мотивам. А нет ли такого шрифта, чтобы символы кириллицы и английские различались в Notepad++? Или плагина к нему. Чистое любопытство.

Share this post


Link to post
Share on other sites
25 минут назад, ViKo сказал:

По мотивам. А нет ли такого шрифта, чтобы символы кириллицы и английские различались в Notepad++? Или плагина к нему. Чистое любопытство.

Элементарно: Любой редактор понимающий разные кодировки, переключаете в другую кодировку (в неправильную) и русские буквы становятся кракозябрами. Например вместо Win1251 включить DOS или KOI.

Ну это конечно только для однобайтовых символов, с Unicode-ом не получится так.

Я все тексты набираю/редактирую в DosNavigator-е, так там это делается нажатием одной кнопки F8.  :good:

Share this post


Link to post
Share on other sites
42 минуты назад, jcxz сказал:

Ну это конечно только для однобайтовых символов, с Unicode-ом не получится так.

Я в UTF-8 пишу. Переключил на ANSI, вместо Т получил Рў. Годится! 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.