Jump to content

    
Sign in to follow this  
ViKo

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

Recommended Posts

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

#include <stdint.h>
#include <assert.h>

constexpr char S1 = 'A';
constexpr char S2 = 'B';
constexpr char S3 = 'C';

template <char First, char ... Other> class Pack
{
public:
	template <> static uint64_t comb(char First)
	{ return First << 8; }
	template <> static uint64_t comb(char ...)
	{ return (First << 8 | comb(Other ...)); }
};

int main(void)
{
	using P = Pack<S1,S2>;
	volatile uint64_t D = P::comb('D','E');
}

Без конструктора оно легально? Мне, как бы, ни к чему. Мне только функции из него нужны. Но это вопрос другой. 

Share this post


Link to post
Share on other sites

Я не очень понял, что нужно.

Просто комбинировать маски? Это просто:

// шаблонная функция с одним параметром (она будет завершать рекурсию)
template <typename First>
uint32_t Comb(First value)
{
    return value;
}

// шаблонная функция с более чем одним параметром. Первый параметр 
// отделяется в First, остальные - упакованы в Other
template <typename First, typename... Other>
uint32_t Comb(First first, Other... other)
{
    return Comb(other...) << 8 | Comb(first);
}

// Применение:
std::cout << Comb('A', 'B', 'C') << std::endl;
std::cout << Comb(2, 1, 1) << std::endl;


// Для c++17 можно проще, через if constexpr:
template <typename First, typename... Other>
uint32_t CombC17(First first, Other... other)
{
	uint32_t value { 0 };
	if constexpr (sizeof...(Other) > 0)
	{
		value = CombC17(other...) << 8;
    }
    value |= first;
    return value;
}

// Примененять так же:
std::cout << CombC17('A', 'B', 'C') << std::endl;
std::cout << CombC17(2, 1, 1) << std::endl;

 

 

 

Share this post


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

Я не очень понял, что нужно.

Просто комбинировать маски?

Это просто пример, первое, что в голову пришло. Хочу класс иметь с разными функциями. Всё для портов STM32.

Вот как эти рекурсивно компилирующиеся шаблоны вставить в класс?

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

И в шаблон я передаю не типы, а значения.

Share this post


Link to post
Share on other sites

Просто вокруг них написать class и поставить скобочки :-)

Получится шаблонный класс (со своими параметрами, типа, номер порта), и внутри него шаблонные функции, со своими параметрами.

Share this post


Link to post
Share on other sites
#include <stdint.h>
#include <assert.h>
#include <iostream>


constexpr char S1 = 'A';
constexpr char S2 = 'B';
constexpr char S3 = 'C';

template <typename First = char, typename ... Other> class Pack
{
public:
	template <First> static uint64_t comb(First value)
	{ return value << 8; }
	template <First, Other...> static uint64_t comb(First value, Other ... values)
	{ return (value << 8 | comb(values ...)); }
};


int main(void)
{
	using namespace std;
	// using P = Pack<S1,S2>;
	// Pack<char, char> P(S1, S2);
	// volatile uint64_t D = P::comb('D','E');
	Pack<char> P;
	std::cout << P.comb(S1, S2);
	// std::cout << Pack<char>.comb(S1, 'B', 'C') << std::endl;
}

Source/VariadicTemplate.cpp(44): error: no matching member function for call to 'comb'
        std::cout << P.comb(S1, S2);
                     ~~^~~~
Source/VariadicTemplate.cpp(30): note: candidate function template not viable: requires single argument 'value', but 2 arguments were provided
        template <First> static uint64_t comb(First value)
                                         ^
Source/VariadicTemplate.cpp(32): note: candidate function template not viable: requires single argument 'value', but 2 arguments were provided
        template <First, Other...> static uint64_t comb(First value, Other ... values)
                                                   ^
1 error generated.

Share this post


Link to post
Share on other sites

Вы бы словами описали, что надо-то.

А так - вот:

template <char portLetter> class Port
{
public:
      static constexpr char portName { portLetter };
    
	template <typename First>
	static uint64_t comb(First value) { return value; }
	template <typename First, typename... Other>
	static uint64_t comb(First value, Other ... values) { return comb(values ...) << 8 | comb(value); }
};



int main()
{
	using PortA = Port<'A'>;
	std::cout << PortA::comb(1, 1, 1) << std::endl;
}

Правда, я не понимаю, зачем тут класс, но раз надо, то пусть будет :-)

Share this post


Link to post
Share on other sites

Словами:

Тяну всё то же. Хочу сделать класс Port со всеми 16-ю битами, их режимами, инициализацией и управлением. Но чтобы можно было не только всеми 16-ю битами манипулировать, но и отдельными группами их - одиночными, парами, четверками, восьмерками (хватит для начала, а в идеале - любого количества). Предполагаю для такого класса в шаблоне задавать режимы всех битов, а для использования в группах иметь отдельные функции - члены класса. И в эти функции передавать параметры, заданные в шаблоне: имя порта, бит, тип входа-выхода, скорость, подтяжку, альт. функцию. 

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

Вопрос 1. Можно ли передать параметры шаблона класса в параметры шаблона функций этого класса?

Share this post


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

Вопрос 2. portName не используется, зачем он? 

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

По остальному чуть позже отвечу. (Пока можете глянуть на вот эту мою заготовку).

Share this post


Link to post
Share on other sites

Я обычно проверяю мелкие вещи вот здесь: https://wandbox.org/

А если надо посмотреть дизассемблер разных компиляторов под разные архитектуры, то есть https://godbolt.org/

Share this post


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

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

Это будет не в стиле STL, т.е. не в стиле общепринятой архитектуры под C++
В стиле STL будет если создадите контейнер для пинов и создадите алгоритмы работы с контейнером пинов.

Алгоритмы - это отдельные  функции или объекты содержащие функции. 

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

Share this post


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

В стиле STL будет если создадите контейнер для пинов и создадите алгоритмы работы с контейнером пинов.

Контейнер = объект (экземпляр). А так можно обойтись классами, без экземпляров. Для эмбеда это плюс.

Share this post


Link to post
Share on other sites
33 minutes ago, AHTOXA said:

Контейнер = объект (экземпляр). А так можно обойтись классами, без экземпляров. Для эмбеда это плюс.

Не, контейнер это специальный класс наделенный определенными свойствами характерными для "контейнеров" STL.

 

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.

Sign in to follow this