Про темплайты в С++

Возьмем простейший шаблон функции с нетипизированными параметрами:

template<int A, int B > int ss(int a, int b) 
{
  return A*a + B*b;
}

void setup() {
Serial.begin(9600);
}

void loop() {
  Serial.print(ss<2,2>(2,3));
}

Вопрос вот такой - как задать в качестве параметра шаблона третий аргумент, являющийся производным от первых двух, что-то типа

template<int A, int B, int (A+B) > int ss(int a, int b) 

Проще наверно будет обьяснить, зачем это надо…
Вот у меня есть функция, код которой зависит от параметров A B. Для всех возможных A B код один, а для случая когда A + B равно 40 - код совершенно другой. Как мне запрограммировать специализацию шаблона для этого “особого” варианта?

ЗЫ шаблон и объявление функции на одной строке - это не моя прихоть, это Ардуино ИДЕ иначе не понимает.

1 лайк

Чтобы понять как отвечать и не слишком долго толочь воду в ступе, скажите, Вы в принципе умеете специализировать шаблон в зависимости от значения параметра? Например, пусть в шаблоне всего один параметр, Вы можете сгенерировать один код для случая, когда он равен 40 и другой код для всех остальных случаев?

И заодно, Вас устроят примеры в Atmel Studio или обязательно в IDE?

хммм… мне кажется что могу… а что тут сложного? Показать как я это сделал бы?

Покажите, чтобы мне понимать о чём речь.

желательно без использования c++20 и даже, если возможно, без c++17

Вот, как раз, начиная с 17 появилась специальная фича для таких фокусов и там это делается естественно, не через зад.

Но, для начала покажите, как Вы это делаете.

template<int A, int B > int ss(int a, int b) 
{
  return A*a + B*b;
}

template<> int ss<2, 3> (int a, int b) 
{
  return a + b;
}

насколько я помню, для функций частичная специализация невозможна, поэтому показываю полную.
Для классов можно и частично.

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

Исправляюсь, вот шаблонный класс с примером частичной специализации:

template<int A, int B > 
class AA 
{
  public:
  int foo() {return A + B;}
};

template<int A > 
class AA<A, 40> 
{
  public:
  int foo() {return A + 22;}
};

AA<2,3> aa;
void setup() {
  // put your setup code here, to run once:
 Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.print(aa.foo());
}

Дебильный вопрос. А классы чё не оптимизируются линковщиком? Кажется уже где то было в дебильних вопросах?

не знаю.
а причем тут это?

Пипец! А я ВСЁ это время писал для Вас пример “обертки” функции в класс (функтора), чтобы обойти это ограничение и воспользоваться частичной специализацией :frowning:

Значит, так, давайте я Вам покажу готовый, работающий функтор (это обёртка класса над функцией, когда в классе определён оператор вызова функции). Думаю, Вы поймёте подход и дальше сделаете для любого класса по образу и подобию сами. Если нет, то пишите в чём проблема, но я сейчас исчезаю и вернусь после хоккея, так что скоро ответов не ждите :frowning:

Работающий пример с функтором
#define printVar(x) do { Serial.print(#x "="); Serial.print(x); Serial.print("; "); } while (false)
#define printVarLn(x) do { Serial.print(#x "="); Serial.println(x); } while (false)

template <int A, int B, int C = A + B> struct Functor { int operator()(int a, int b) {return A*a + B*b; } };
template <int A, int B> struct Functor<A, B, 40> { int operator()(int a, int b) {return a + b; } };

void setup(void) {
   Serial.begin(9600);
   Serial.println("Let's go!");

   Functor<20,21> ss1;
   Functor<19,21> ss2; // равно 40

   int s1 = ss1(2,3);  // Должно быть 103
   int s2 = ss2(2,3);  // Должно быть 5

   printVarLn(s1);
   printVarLn(s2);
}

void loop(void) {}

Кстати, посмотрите как бы красиво и просто всё решалось в

С++17 с if constexpr
template<int A, int B> int ss(int a, int b) {
   if constexpr (A+B == 40) {
      return a + b;
   } else {
      return A*a + B*b;
   }
}
1 лайк
	template<int A, int B> int ss() { 
		if constexpr (A + B == 40) {
			return 1;
		} else {
			return 2;
		}
	}
1 лайк

прошу прощения, все новички одинаковы, пытаются показать пример “как попроще”, а получается фигня

template<int A, int B, int C = A + B > 
class AA 
{
  public:
  int foo() {return A + B;}
};

template<int A, int B > 
class AA< A, B, 40> 
{
  public:
  int foo() {return A + 22;}
};

AA<2,3> aa;
AA<2,38> bb;

так просто???
Какого же фига ни в одном пособии по шаблоном этого нет?

я не знаю, что может быть проще тем третий параметр как int C = A + B… и работает в любом компиляторе :slight_smile:

@ЕвгенийП
Огромное спасибо!

Еще раз извините, что заставил выдумывать сложное решение в простом случае.

так тебе пойдёт?

template<int A,  int B, int S> class _first 
{
  public:
  _first () {
    Serial.printf("First example for %d %d %d\n", A, B, S);
  }
};

template<int A, int B> class _first<A,B, 50> 
{
  public:
  _first () {
    Serial.printf("First example SPECIAL!!!  %d %d\n", A, B);
  }
};

template<int A, int B> class First {
  _first<A,B,A+B> _firstExample;
}; 




void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);
  Serial.println("Hello, ESP32!");

  First<10,11> e1;
  First<24,26> e2;
  }

void loop() {
  // put your main code here, to run repeatedly:
  delay(10); // this speeds up the simulation
}

Вот вывод вокви:

Hello, ESP32!

First example for 10 11 21
First example SPECIAL!!!  24 26

1 лайк

ой, блин!!! А ты сам нашел про специализацию! Малацца! Пока я пример собирал в вокви, ты и сам справился!

это как-бы подразумевается. В шаблоне ты используешь типовое определение переменной, в нем может быть инициализатор. далее - по тексту стандарта. Но да, изучение С++ творческое занятие. Угадывать многое нужно :wink:

так тоже можно, спасибо

Спасибо, одна из самых интересных и полезных тем за пару месяцев.
Как бы настроить личную копилку полезных топиков

1 лайк

Так тут же избранное есть:

1 лайк