Инициализация переменных функции
Поиграв с некоторыми примерами, я нашел следующую конструкцию:
void Show(int nav = 0) // -1 сверху, 1 снизу
и мне стало интересно, какой эффект имеет инициализация параметров хендовера в объявлениях функций, я никогда сознательно не замечал такой конструкции.
Итак, я сделал небольшую демонстрацию:
#include <M5Stack.h> //необходимо для моей платы
int a;
int b;
int c;
int addFunction(int x = 3, int y = 3){
int result;
result = x + y;
return result;
}
void setup(){
Serial.begin(9600);
// тестовый пример 1
a = 1;
b = 2;
c = addFunction(a, b);
Serial.println("testcase 1:");
Serial.println((String)a + " + " + b + " = " + c);
// тестовый пример 2
a = 1;
b = 2;
c = addFunction();
Serial.println("testcase 2:");
Serial.println((String)a + " + " + b + " = " + c);
// тестовый пример 3
a = 1;
b = 2;
c = addFunction(a);
Serial.println("testcase 3:");
Serial.println((String)a + " + " + b + " = " + c);
}
void loop() {
}
Вывод:
Итак, я узнал:
если вы передаете параметры, инициализация игнорируется, если вы вызываете функцию без передачи параметров, функции работают со значениями инициализации.
если вы передаете только один параметр, он будет присвоен первому в объявлении .
Вопрос:
Существует ли синтаксис, позволяющий вызывать функцию только со вторым параметром, чтобы в качестве первого параметра использовалось инициализированное значение объявления? В этом примере с a = 1, b = 2 вы передаете только b, а ожидаемый результат будет 5.
@RJPlog, 👍1
Обсуждение2 ответа
Лучший ответ:
Это (к сожалению) вопрос не по Arduino. На самом деле речь идет о синтаксисе C++, который является довольно сложным языком.
Обнаруженный вами механизм называется аргументами по умолчанию. Прототип или определение функции могут содержать значения аргументов по умолчанию. Поскольку это список, значения по умолчанию ограничены справа налево. Невозможно использовать параметр по умолчанию для аргумента слева от данного аргумента. Порядок строго справа налево.
f(int x = 0, int y = 1, int z = 2)
f(1,2,3) binds x = 1, y = 2, z = 3
f(1,2) equals f(1,2,2) binds x = 1, y = 2, z = 2
f(1) equals f(1,1,2) binds x = 1, y = 1, z = 2
f() equals f(0,1,2) binds x = 0, y = 1, z = 2
В C++ существует синтаксис инициализации структуры (также известный как агрегатная инициализация), который позволяет присваивать имена значениям полей структуры. Этот тип именования не допускается для вызовов функций.
Прочитайте https://en.cppreference.com/w/cpp/language/default_arguments , https://en.cppreference.com/w/cpp/language/aggregate_initialization и https://en.cppreference.com/w/cpp/utility/functional/bind для получения более подробной информации. И хорошая книга по C++.
Существуют языки, которые допускают аргументы по умолчанию и именованные параметры, например C#, Python, Ruby и Smalltalk. См. https://en.wikipedia.org/wiki/Named_parameter.
Удачи!
(Обновление)
Ниже приведена переписанная версия @VE7JRO Добавить класс функции с использованием оператора приведения для выполнения оценки:
class Add
{
public:
Add(int x, int y) : m_x(x), m_y(y) {}
operator int() { return m_x + m_y; }
void x(int x) { m_x = x; }
void y(int y) { m_y = y; }
int print(Print& outp) {
int res;
res = outp.print(F("Add(x="));
res += outp.print(m_x);
res += outp.print(F(",y="));
res += outp.print(m_y);
res += outp.print(F(")"));
return res;
}
private:
int m_x, m_y;
};
Add func(1,2);
void setup() {
Serial.begin(9600);
func.print(Serial);
Serial.print(F("="));
Serial.println(func);
func.x(12);
func.print(Serial);
Serial.print(F("="));
Serial.println(func);
func.y(13);
func.print(Serial);
Serial.print(F("="));
Serial.println(func);
}
void loop() {
}
Хорошее объяснение и материал для дальнейшего расследования, также спасибо за расширение @VE7JRO, оно добавляет еще несколько интересных для меня деталей. (после того, как я проверил, что вы используете другую скорость передачи данных ;-)), @RJPlog
Пропустил разницу в скорости передачи данных. Это изменено, чтобы избежать путаницы, отладки и т. д. между эскизами., @Mikael Patel
BW: Если данные члена станут общедоступными, будет разрешен синтаксис func.x = 12
(после удаления префикса m_
)., @Mikael Patel
Если ваша функция находится внутри класса, вы можете установить любую переменную, обе переменные или использовать значения по умолчанию.
class Add{
int a, b;
public:
Add(): a(1), b(2){}
int AddTwoIntegers(){
return a + b;
}
void SetInt1(int int1){
a = int1;
}
void SetInt2(int int2){
b = int2;
}
};
Add Test1;
void setup(){
Serial.begin(9600);
Serial.print("Test default values = ");
Serial.println(Test1.AddTwoIntegers());
Test1.SetInt2(4);
Serial.print("Set b = 4 then add to a = ");
Serial.println(Test1.AddTwoIntegers());
}
void loop(){}
понял, спасибо за пример, очень помог мне в понимании, пока пробовал, @RJPlog
- Невозможно преобразовать 'int (*)[size]' в 'int**': Cannot convert 'int (*)[size]' to 'int**'
- Как удалить элемент из массива arduino?
- Как передать несколько переменных в функцию?
- Есть ли функция Adafruit для инвертирования цветов моего экрана для языка Arduino?
- Как вернуть значение массива символов в функции Arduino IDE?
- Проблема с функцией, имеющей параметр со значением по умолчанию
- Ошибка: Переменная или поле объявлены недействительными
- Как получить переменную из функции обратного вызова?
Должен ли всегда быть один параметр для второго параметра (добавление перегруженной функции) или вы хотите выбрать, для какого параметра?, @Jot
Это просто общий вопрос для понимания синтаксиса. Вот мне был бы интересен ответ как это сделать вообще, а значит еще и с большим количеством параметров и возможностью выбора любого параметра в зависимости от цели (m из n), @RJPlog
Перегруженная функция — это один из вариантов приема различного количества параметров. Указатель может иметь значение nullptr (или NULL), и в коде вы можете проверить наличие nullptr. Должны быть и другие варианты., @Jot
@Jot Tanks за подсказку. Я посмотрел на это, думаю, это из-за того, что я не работаю, поскольку x и y имеют один и тот же тип. Я проверю, заработает ли он, возможно, с разными типами., @RJPlog