Jump to content

    

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

19 minutes ago, dxp said:

Этот термин идёт из языков,

Кажется, я узнал кучу новых терминов: "объект первого класса", "функтор". Вернее я их слышал, но не предавал им значения...:dance4:

Share this post


Link to post
Share on other sites
3 hours ago, haker_fox said:

Кажется, я узнал кучу новых терминов: "объект первого класса", "функтор". Вернее я их слышал, но не предавал им значения...:dance4:

И забудьте сразу это словоблудие. Если конечно не хотите потролить кого-нибудь.
Понятие функтор вы не найдете в справочнике по C++, как и понятие "объекты первого класса" тоже метафора рожденная не от C++.   
Так что я б посылал лесом такую терминологию, она засоряет понимание плюсов.
Лябды - это функции-объекты, но не любые какие вздумается. И они обязательно должны иметь функцию. Поэтому и зовут их лямбда-выражения.
Это феномен в себе не подлежащий редуцированию или выводу из других сущностей.    
Я сам привел понятие "функтор" только чтоб развеселить тему. 

Share this post


Link to post
Share on other sites
4 часа назад, dxp сказал:

Лямбда-функция в С++ - это анонимный функтор. Согласитесь, что функтор и функция - это разные вещи. Первый - это объект (первого класса в том числе), вторая просто код.

Соглашусь, что разные. Функтор - это класс с перегруженным operator(), предназначенный для манипулирования объектами контейнера.
Не соглашусь, что лямбда-функция - это функтор. Лямбда-выражения в C++ используются именно в виде анонимных функций, без имени, адреса, используемых в месте определения.
Насчет порядка функций - это, видимо, из питона и т.п. термин. В учебниках по C/C++/C# не встречал. Да и какой может быть порядок, если вложенные функции невозможны. Кроме этих лямбд.
Нисколько не сомневаюсь, что вы продвинутый программист и в теории и на практике. Однако, лямбда-функция означает лямбда в форме функции. Или наоборот. И уж точно не было корректным ваше безоговорочное "не функции вообще". 

Share this post


Link to post
Share on other sites
22 minutes ago, ViKo said:

Соглашусь, что разные. Функтор - это класс с перегруженным operator(), предназначенный для манипулирования объектами контейнера.
Не соглашусь, что лямбда-функция - это функтор. Лямбда-выражения в C++ используются именно в виде анонимных функций, без имени, адреса, используемых в месте определения.
Насчет порядка функций - это, видимо, из питона и т.п. термин. В учебниках по C/C++/C# не встречал. Да и какой может быть порядок, если вложенные функции невозможны. Кроме этих лямбд.
Нисколько не сомневаюсь, что вы продвинутый программист и в теории и на практике. Однако, лямбда-функция означает лямбда в форме функции. Или наоборот. И уж точно не было корректным ваше безоговорочное "не функции вообще". 

Все равно не понял, чего вы хотите. Так что - ли ?

template<typename T, typename... Args>
class Pack {
public:
	static T comb(T v) {
		return v << 8;
	}
	static T comb(T first, Args... args) {
		return (first << 8) | comb(args...);
	}

};


int main(void)
{
	long sum = Pack<char, char>::comb(1,2);
	return 0;
}

 

Share this post


Link to post
Share on other sites

Так, да не так, DASM. 

Я хочу в шаблон класса передать не типы, а значения. Типы я и так знаю. Они не меняются. И вот прибыл в лингвистический тупик. 

Share this post


Link to post
Share on other sites
52 minutes ago, ViKo said:

Так, да не так, DASM. 

Я хочу в шаблон класса передать не типы, а значения. Типы я и так знаю. Они не меняются. И вот прибыл в лингвистический тупик. 

Ну  тогда до с++17 похоже что ничего не выйдет

!

When instantiating a class template, we have to pass in the types explictly (at least until C++17):


But when instantiating a function template, the compiler can often figure the types out:

Не надо в класс короче пихать.

https://foonathan.net/2016/11/template-argument-deduction/

Share this post


Link to post
Share on other sites
16 minutes ago, ViKo said:

Не-ти-по-вой параметр!

http://ci-plus-plus-snachala.ru/?p=3989

так у него тип явно указан - template <typename T, int MAXSIZE>

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

Вот template<auto n> struct B { /* ... */ };

B<5> b1; 

VS 2017 это не переварил в С++ 17 , но скушал в "ISO C++ Latest Draft Standard (/std:c++latest)"

Писать на новейших драфтах для mcu это конечно шикарно..

 

Share this post


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

так у него тип явно указан - template <typename T, int MAXSIZE>

И я укажу. Я свои типы знаю.

Не могу передать эти параметры в шаблонные функции. Об этом и спрашивал в стартовом сообщении.

Share this post


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

И я укажу. Я свои типы знаю.

Не могу передать эти параметры в шаблонные функции. Об этом и спрашивал в стартовом сообщении.

в стартовом было вообще нечто несвязное. Далее прояснили "Не получается задать в шаблоне значения и по ним функции определять внутри класса."

Теперь стало вообще ничего непонятно.

Share this post


Link to post
Share on other sites

Ну вот, набросал кусочек.

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

// тестовая структура для проверки работы класса порта
struct PortStruct
{
	volatile uint32_t pinValues;  // значения ног
	volatile uint32_t pinDirs;    // направления ног (0 = вход)
};

// это у нас будут типа регистры портов. 
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);
	}

	// чтение/запись порта целиком
	static void set(uint32_t value) { getPortStruct()->pinValues = value; }
	static uint32_t get() { return getPortStruct()->pinValues; }

	// чтение одной ножки порта
	static void setPin(int pinNum, bool on) {
		if (on)
			getPortStruct()->pinValues |= (1UL << pinNum);
		else
			getPortStruct()->pinValues &= ~(1UL << pinNum);
	}

	// вложенный класс "шина"
	template<unsigned... Pins>
	struct Bus
	{
		// выдать маску шины (единички в тех позициях, которые включены в эту шину)
		static constexpr uint32_t getMask()	{
			return getMask<Pins...>();
		}

		// прочитать значение шины (только те биты, которые включены в шину)
		static uint32_t get() {
			auto result { 0u };
			for (auto pin = 0u,  mask =  getMask(), value = Port::get() & mask; value; mask >>= 1, value >>= 1) {
				if (mask & 1u) {
                    if (value & 1u)
                        result |= (1u << pin);
                    ++pin;
                }
			}
			return result;
		}

		// запись значения в шину
		static void set(unsigned value) {
			for (auto mask = getMask(), pin = 0u; mask; mask >>= 1, ++pin) {
				if (mask & 1u) {
					Port::setPin(pin, value & 1);
					value >>= 1;
				}
			}
		}

	private:

		// вспомогательная шаблонная функция для вычисления маски шины
		template<uint32_t FirstPin, uint32_t... OtherPins>
		static constexpr uint32_t getMask() {
			uint32_t value { 0 };
			if constexpr (sizeof...(OtherPins) > 0)	{
				value = getMask<OtherPins...>();
			}
			value |= (1 << FirstPin);
			return value;
		}

	};

};

int main()
{
	using PortA = Port<'A'>;

	PortA::setPin(1, true);   // установим бит 1 в единичку
	std::cout << "Читаем порт, должно быть число 2: " << PortA::get() << std::endl;

	PortA::setPin(2, true);   // установим бит 2 в единичку
	std::cout << "Читаем порт, должно быть число 6: " << PortA::get() << std::endl;

	PortA::set(0);
	std::cout << "Читаем порт, должно быть число 0: " << PortA::get() << std::endl;

	// шина из битов 0, 2, 4 порта A
	using PortA_Pins024 = PortA::Bus<0, 2, 4>;
	static_assert (PortA_Pins024::getMask() == 21, "");  // проверим маску. 

	std::cout << "Читаем шину, должно быть число 0: " << PortA_Pins024::get() << std::endl;

	PortA_Pins024::set(1);
	std::cout << "Читаем шину, должно быть число 1: " << PortA_Pins024::get() << std::endl;
	std::cout << "Читаем порт, должно быть число 1: " << PortA::get() << std::endl;

	PortA_Pins024::set(2);
	std::cout << "Читаем шину, должно быть число 2: " << PortA_Pins024::get() << std::endl;
	std::cout << "Читаем порт, должно быть число 4: " << PortA::get() << std::endl;
	PortA_Pins024::set(3);
	std::cout << "Читаем шину, должно быть число 3: " << PortA_Pins024::get() << std::endl;
	std::cout << "Читаем порт, должно быть число 5: " << PortA::get() << std::endl;
}

Можно потыкать вот тут. Думаю, идея понятна.

Share this post


Link to post
Share on other sites

Спасибо, Антон!
Запись одной ножки пропустили. Вернее, запись есть, а в комментарии написано "чтение", а чтения нет.
И я не вижу, как getMask для одного параметра работает. А, это в конце, нашёл. Ага, sizeof... использовали. Вот оно, решение вопроса по теме.

Share this post


Link to post
Share on other sites

Да, запись ножки есть, комментарий не соответствует. Чтение по аналогии, там тривиально.

getMask в случае одного параметра обрабатывается в ветке if constexpr()... Вернее, когда параметр один, то эта ветка не выполняется.

Это вариант для c++17. Если c++11, то придётся делать две функции - с одним параметром и с несколькими.

Share this post


Link to post
Share on other sites
28 minutes ago, ViKo said:

 Вот оно, решение вопроса по теме.

Какое же это решение. 
Простейший цикл for завернули в многоэтажный нечитабельный шаблон.
При этом наблюдается отсутствие детерминизма. Про потокозащищенность даже молчу.  
При реальном количестве портов их свойств этот шаблов превратится в монстра. 

А ведь можно было обойтись простым и ясным массивом. 
Что ни говорите, но плюсам не тягаться с простыми операторами C в этом деле.   

Share this post


Link to post
Share on other sites

Это именно то, что я спрашивал. Будем смотреть, во что компилируется, а не сколько в нём этажей. 

Есть мысли сделать класс полного порта и наследственный класс на произвольное количество выводов. 

В результате должно компилироваться в команды, обращающиеся непосредственно к регистрам GPIO. 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now