Специализация шаблона функции с параметром не-типом
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 09.11.18 18:01
Оценка:
Здравствуйте!

Неумею я что-то в сабж.
Пытаюсь сделать
  что-то такое
#include <iostream>
using namespace std;

typedef struct {
    unsigned v;
} GPIO_typedef;


#define PORTA  ((GPIO_typedef*)0x04)
#define PORTB  ((GPIO_typedef*)0x08)

template< GPIO_typedef* T >
inline
unsigned getPortFlag()
{
    //static_assert(false, "not implemented for this target");
    return 0;
}

template<  >
inline
unsigned getPortFlag< PORTA >()
{
    return 1;
}



int main() {
    // your code goes here
    
    cout<<"Port A flag: "<<getPortFlag<PORTA>()<<"\n";
    cout<<"Port B flag: "<<getPortFlag<PORTB>()<<"\n";
    return 0;
}

В Keil'е получаю совсем невнятное сообщение, сейчас не приведу, а скинуть с работы забыл
В GCC немного попонятнее:

prog.cpp:22:10: error: template-id ‘getPortFlag<4u>’ for ‘unsigned int getPortFlag()’ does not match any template declaration
unsigned getPortFlag< PORTA >()
^~~~~~~~~~~~~~~~~~~~
prog.cpp:14:10: note: candidate is: template<GPIO_typedef* T> unsigned int getPortFlag()
unsigned getPortFlag()
^~~~~~~~~~~
prog.cpp: In function ‘int main()’:
prog.cpp:32:44: error: no matching function for call to ‘getPortFlag()’
cout<<"Port A flag: "<<getPortFlag<PORTA>()<<"\n";
^
prog.cpp:14:10: note: candidate: template<GPIO_typedef* T> unsigned int getPortFlag()
unsigned getPortFlag()
^~~~~~~~~~~
prog.cpp:14:10: note: template argument deduction/substitution failed:
prog.cpp:32:44: error: ‘4u’ is not a valid template argument for ‘GPIO_typedef*’ because it is not the address of a variable
cout<<"Port A flag: "<<getPortFlag<PORTA>()<<"\n";
^



Но всё равно что-то не догоняю, как правильно сделать.

И еще, похоже я не имею готовить static_assert — по задумке, если не нашлось нужной специализации, то он должен выстрелить, а он сразу стреляет. Хотя, это может из-за того, что со специализацией косяк
Маньяк Робокряк колесит по городу
Отредактировано 09.11.2018 21:37 Marty . Предыдущая версия .
Re: Специализация шаблона функции с параметром не-типом
От: reversecode google
Дата: 09.11.18 18:49
Оценка:
#include <iostream>
using namespace std;

#define PORTA (intptr_t)0x04
#define PORTB (intptr_t)0x08

template< intptr_t T >
inline
unsigned getPortFlag()
{
//static_assert(false, "not implemented for this target");
return 0;
}

template< >
inline
unsigned getPortFlag< PORTA >()
{
return 1;
}



int main() {
// your code goes here

cout<<"Port A flag: "<<getPortFlag<PORTA>()<<"\n";
cout<<"Port B flag: "<<getPortFlag<PORTB>()<<"\n";
return 0;
}

Port A flag: 1
Port B flag: 0
Re: Специализация шаблона функции с параметром не-типом
От: watchmaker  
Дата: 09.11.18 18:51
Оценка: 4 (1)
Здравствуйте, Marty, Вы писали:

M> я не имею готовить static_assert — по задумке, если не нашлось нужной специализации, то он должен выстрелить, а он сразу стреляет.

Конечно. Если конструкция static_assert(false) написана вне комментариев, то код с ней никогда не скомпилируется — она же всегда ложна.

Конкретно тут компилятор видит, что условие в static_assert не зависит от параметров шаблона, а значит он обязан его вычислить на первой стадии (из двух, которые two-phase name lookup). Он его вычисляет и завершает компиляцию.

То, что ты хочешь, можно сделать перенеся проверку на вторую стадию, например написав static_assert(T != T, ...);
Re[2]: Специализация шаблона функции с параметром не-типом
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 09.11.18 18:56
Оценка:
Здравствуйте, reversecode, Вы писали:


R>
R>#include <iostream>
R>using namespace std;

R>#define PORTA (intptr_t)0x04
R>#define PORTB (intptr_t)0x08
R>



Проблема в том, что: 1) выделенное определено не мной, а в сторонней библиотеке; 2) Бывает typedef не только GPIO_typedef, а и TIM_typedef, ADC_Typedef etc, и для всех них нужно получить кое-какую информацию в зависимости от типа и конкретного значения
Маньяк Робокряк колесит по городу
Re[2]: Специализация шаблона функции с параметром не-типом
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 09.11.18 18:58
Оценка:
Здравствуйте, watchmaker, Вы писали:


W>То, что ты хочешь, можно сделать перенеся проверку на вторую стадию, например написав static_assert(T != T, ...);


Спс. А по первой части вопроса нет идей?
Маньяк Робокряк колесит по городу
Re[3]: Специализация шаблона функции с параметром не-типом
От: reversecode google
Дата: 09.11.18 19:57
Оценка:
адреса определите статиками
и уберите или переосмыслите ваши шаблоны а то их смысл не понятен
Re[4]: Специализация шаблона функции с параметром не-типом
От: reversecode google
Дата: 09.11.18 19:59
Оценка:
https://stackoverflow.com/questions/43846311/how-to-set-a-constexpr-pointer-to-a-physical-address
https://arne-mertz.de/2017/06/stepping-away-from-define/
Re: Специализация шаблона функции с параметром не-типом
От: Vamp Россия  
Дата: 09.11.18 20:17
Оценка:
M>Неумею я что-то в сабж.
Дело не в этом. Дело в том, что проблема нерешаема в принципе. Нетиповой (non-type) аргумент шаблона должен быть константным выражением. А твой reinterpret_cast из целочисленной константы (0x04) в указатель нарушает это правило, потому что константное выражение не может содержать reinterpret_cast. У тебя и без специализации ничего не работало.

Если эти тупые define тебе даны от бога (очень похоже на легаси С), то смирись — шаблоны тут неприменимы.
Да здравствует мыло душистое и веревка пушистая.
Отредактировано 09.11.2018 20:18 Vamp . Предыдущая версия .
Re[4]: Специализация шаблона функции с параметром не-типом
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 09.11.18 21:21
Оценка:
Здравствуйте, reversecode, Вы писали:


R>адреса определите статиками


Адреса заданы в чужом коде же


R>и уберите или переосмыслите ваши шаблоны а то их смысл не понятен


Вот "за переосмыслить" я и пришел сюда. Смысл — повторюсь — получить некоторую мною навешенную информацию в зависимости от типа тайпдефа и конкретного значения
Маньяк Робокряк колесит по городу
Re[2]: Специализация шаблона функции с параметром не-типом
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 09.11.18 21:30
Оценка:
Здравствуйте, Vamp, Вы писали:


M>>Неумею я что-то в сабж.

V>Дело не в этом. Дело в том, что проблема нерешаема в принципе. Нетиповой (non-type) аргумент шаблона должен быть константным выражением. А твой reinterpret_cast из целочисленной константы (0x04) в указатель нарушает это правило, потому что константное выражение не может содержать reinterpret_cast. У тебя и без специализации ничего не работало.

V>Если эти тупые define тебе даны от бога (очень похоже на легаси С), то смирись — шаблоны тут неприменимы.


Это SPL от STM — те самые тупые define'ы

Ясно. Спасибо

ЗЫ А constexpr не спасет отца русской демократии?
Просто подумал, что придется в итоге сделать тупую перегрузку функции по типу typedef'а, а там внутри if'ами выбирать результат в зависимости от значения аргумента. В принципе, большой беды не будет, если оно и в рантайме будет работать, но пару байт сэкономить тоже не грех — на некоторых STMках флеша всего 4Кб. Если constexpr привесить, оно в компайл-тайм вычислится?
Маньяк Робокряк колесит по городу
Re: Специализация шаблона функции с параметром не-типом
От: kov_serg Россия  
Дата: 10.11.18 05:08
Оценка: :)
Здравствуйте, Marty, Вы писали:

M>Но всё равно что-то не догоняю, как правильно сделать.

Будьте проще:
#define MYFLAG_PORTA 1
#define MYFLAG_PORTB 0

#define MYFLAG(port) MYFLAG_##port

int main() {
    cout<<"Port A flag: "<<MYFLAG_PORTA<<"\n";
    cout<<"Port B flag: "<<MYFLAG(PORTB)<<"\n";
    return 0;
}
Re[3]: Специализация шаблона функции с параметром не-типом
От: Vamp Россия  
Дата: 11.11.18 18:30
Оценка:
M>Просто подумал, что придется в итоге сделать тупую перегрузку функции по типу typedef'а, а там внутри if'ами выбирать результат в зависимости от значения аргумента. В принципе, большой беды не будет, если оно и в рантайме будет работать, но пару байт сэкономить тоже не грех — на некоторых STMках флеша всего 4Кб. Если constexpr привесить, оно в компайл-тайм вычислится?
Нет. Потому, что аргумент не будет константным выражением, см. выше. Но если аргумент функции известен на этапе компиляции, то с вероятностью 100% сработает оптимизация, и никаких вычислений в ран-тайме не будет. Можешь проверить asm и убедиться.
Да здравствует мыло душистое и веревка пушистая.
Re: Специализация шаблона функции с параметром не-типом
От: B0FEE664  
Дата: 12.11.18 09:05
Оценка: 1 (1) :)
Здравствуйте, Marty, Вы писали:

M>Пытаюсь сделать

M>
  что-то такое
M>
#include <iostream>
M>using namespace std;

M>typedef struct {
M>    unsigned v;
M>} GPIO_typedef;


M>#define PORTA  ((GPIO_typedef*)0x04)
M>#define PORTB  ((GPIO_typedef*)0x08)

M>template< GPIO_typedef* T >
M>inline
M>unsigned getPortFlag()
M>{
M>    //static_assert(false, "not implemented for this target");
M>    return 0;
M>}

M>template<  >
M>inline
M>unsigned getPortFlag< PORTA >()
M>{
M>    return 1;
M>}



M>int main() {
M>    // your code goes here
    
M>    cout<<"Port A flag: "<<getPortFlag<PORTA>()<<"\n";
M>    cout<<"Port B flag: "<<getPortFlag<PORTB>()<<"\n";
M>    return 0;
M>}

M>




Если рассматривать задачу как этюд, то решить, конечно, можно:

#include <iostream>
using namespace std;

typedef struct {
    unsigned v;
} GPIO_typedef;


#define PORTA  ((GPIO_typedef*)0x04)
#define PORTB  ((GPIO_typedef*)0x08)


#define MKSTR2(TOSTR) #TOSTR 
#define MKSTR(TOSTR) MKSTR2(TOSTR)[19]

template< char ch >
inline
unsigned getPortFlag()
{
    //static_assert(false, "not implemented for this target");
    return 0;
}

template<  >
inline
unsigned getPortFlag< MKSTR(PORTA) >()
{
    static_assert('4' == MKSTR(PORTA), "port A?");
    return 1;
}



int main() {
    // your code goes here
    
    cout<<"Port A flag: "<<getPortFlag<MKSTR(PORTA)>()<<"\n";
    cout<<"Port B flag: "<<getPortFlag<MKSTR(PORTB)>()<<"\n";
    return 0;
}


тест

Но вставлять в продукшен я бы не стал.
И каждый день — без права на ошибку...
Re[2]: Специализация шаблона функции с параметром не-типом
От: ArtDenis Россия  
Дата: 12.11.18 15:49
Оценка:
Здравствуйте, Vamp, Вы писали:

V>Если эти тупые define тебе даны от бога (очень похоже на легаси С), то смирись — шаблоны тут неприменимы.


Если я правильно понял проблему, то я обошёл её вот таким путём:
https://github.com/art-den/co2meter/blob/master/firmware/src/stm32_lib/hl_gpio.hpp
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re: Специализация шаблона функции с параметром не-типом
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 15.11.18 21:12
Оценка:
Здравствуйте, Marty, Вы писали:

M> Здравствуйте!


M>Неумею я что-то в сабж.


Спасибо всем за советы, решил забить на constexpr, и в принципе все хорошо получилось, с вашей, коллеги, помощью
Маньяк Робокряк колесит по городу
Re[3]: Специализация шаблона функции с параметром не-типом
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 15.11.18 22:07
Оценка:
Здравствуйте, ArtDenis, Вы писали:

V>>Если эти тупые define тебе даны от бога (очень похоже на легаси С), то смирись — шаблоны тут неприменимы.


AD>Если я правильно понял проблему, то я обошёл её вот таким путём:

AD>https://github.com/art-den/co2meter/blob/master/firmware/src/stm32_lib/hl_gpio.hpp

Спасибо за совет. Правда я в итоге сделал всё далеко не так . Получилось поприятнее, чем у тебя. Показать не могу, сорри — на работе заругают Коротенько опишу только идеи

Тактирование. Нужно получить указатель на функцию тактирования и флаг, который ей передать. Сделал на шаблончиках, некоторая диспечеризация со специализацией шаблонов и на нижнем уровне немного бойлер-плейта с препроцессором и условной компиляцией, потому как семейства STMок отличаются друг от друга, но при внимательном изучении оказалось, что не все так плохо и есть много общего.
За полдня или меньше забил все по F1, F3, F4 — то, что мне непосредственно сейчас нужно. Любая периферия тактируется теперь так:
periphInitClock(GPIOB);
periphInitClock(TIM1);
periphInitClock(I2C2);
// ...



Альтернативные функции. Там было посложнее, пришлось присунуть вариадики, но в итоге тоже при использовании сводится к простому:
initPeriph( I2C2
          , makePeriphPinMode( PA8, I2cPinMode::scl)
          , makePeriphPinMode( PA9, I2cPinMode::sda)
          );



GPIO. У F3/F4 структуры одинаковые, и ширше, чем у F1 — можно больше комбинаций наплодить, правда, непонятно, а надо ли, что из них будет работать, а что нет —
Поэтому режим пина PinMode свел к enum 1 в 1 как у F1 — для F3/F4 в меру разумения заполнил остальные поля сам.

Сделал структуру GpioPinAddr — там порт и номер пина, сделал класс GpioPin — который принимает GpioPinAddr и режим PinMode — in/out/etc. Если что не так — кидаются ассерты.
Нагенерил макросов PA0-PA15, PB0-... — https://ideone.com/rZY85U
Перегрузил операторы и делаю теперь так:
int main()
{
    GpioPin blinkLed(PA8);
    while(true)
    {
        delayMs(500);
        blinkLed = !blinkLed;
    }
}



В общем, стало так же приятно работать, как на ардуинке, и даже удобнее Боль по настройке периферии ушла, осталась только радость от хорошей работы


ЗЫ Если не забуду и будет время, стащу с работы прототипы основных шаблонов для иллюстрации идей
Маньяк Робокряк колесит по городу
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.