Видимость функций.

blokerun2
Offline
Зарегистрирован: 27.01.2019

Есть программа, которая в цикле должна перебирать массив указателей на функции и вызывать данные функции, получая от них значения. Я сильно упростил код, просто для понимания, почему выдает ошибку при компиляции. Ошибка такая: test_pointer:17:27: error: 'can1' was not declared in this scope                     float (*pScan[3])() = {can1, can2, can3};

Есть 3 файла - сам скетч, заголовочный .h и .cpp. Создан класс TEST. Когда помещаю  функции can1(), can2(), can3() в сам скетч, то ошибки нет. Но мне нужно чтобы функции находились в описании класса. Почему не видны имена функций в строке float (*pScan[3])() = {can1, can2, can3}; ?

файл скетча:

#include "test_pointer.h"

float dataSensors[3];

TEST test;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
}

void loop()
{ 
   float (*pScan[3])() = {can1, can2, can3};
   for(int i = 0; i < 3; i++){
    dataSensors[i] = pScan[i]();  
    Serial.print("Sensor" + String(i+1));
    Serial.print(" Value= ");
    Serial.print(dataSensors[i]);   
   } 
 Serial.println();
delay(1000);
}

Файл test_pointer.h:


class TEST{
	public: 
	
	float can1();
	float can2();
	float can3();
};

Файл test_pointer.cpp :

#include "test_pointer.h"

float TEST::can1(){
	return 12.7;
}

float TEST::can2(){
	return 43.5;
}

float TEST::can3(){
	return 66.7;
}
 
 
rkit
Offline
Зарегистрирован: 23.11.2016

Так нельзя, потому что при вызове метод не будет относиться ни к какому экземпляру класса. Используй std::function и лямбды

blokerun2
Offline
Зарегистрирован: 27.01.2019

Благодарю! Но я начинающий и придется изучить эти 2 новые темы- пространство имен и лямбдя-выражения))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да не нужны Вам никакие лямбды, и уж тем более std - он Вас троллит!

Вы лучше ответьте на два вопроса. 

1. Вам точно надо, чтобы Ваши can1/can2/can3 были методами класса?
2. Если да, то второй вопрос - их точно незя сделать статическими методами?

Ответьте, и я покажу Вам как это делается. Неохота показывать то, что не пригодится.

sadman41
Offline
Зарегистрирован: 19.10.2016

Судя по случаю с "ICMP 3,4" не троллит, а просто пишет абы чо. От великого ума или по глупости - вопрос, конечно, дискуссионный.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

я в указателях ничего не понимаю,. но если бы даже что-то понимал то
 

 float (*pScan[3])() = {test.can1, test.can2,test.can3};

 

rkit
Offline
Зарегистрирован: 23.11.2016

Троллит тот, кто пишет "не нужен std".

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

я в указателях ничего не понимаю,. но если бы даже что-то понимал то
 

 float (*pScan[3])() = {test.can1, test.can2,test.can3};

 

В общем, да, но скорее всего нарвётесь на варнинг и, главное, смысл? Что Вам это даст?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

не, не откомпилируется...что-то мне в этой конструкции тоже не нравится, визуально

адрес 16-ти битный, указатель аналогично, с флоатами тут что-то не то
 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Как все, (акромя ТС)  возбудились-то!

В общем, blokerun2, мне уходить надо, не буду ждать Вашего ответа.

Вызывать нестатическую функцию-член вне контекста экземпляра не имеет смысла (даже если удастся). Вы же не можете просто взять анализ там крови, Вы всегда берёте его у кого-то! Так и Ваша can1 - она не существует сама по себе - она существует только у какого-то конкретного экземпляра класса TEST.

Поэтому брать указатель (смещение) можно просто на метод класса TEST (без указания экземпляра), а вот вызывать можно только в контексте экземпляра.

В Вашей программе есть экземпляр test, вот в контексте его и надо вызывать.

Я сделал минимальные изменения в Вашей программе - разбирайтесь (остальные файлы не менялись).

#include "test_pointer.h"

float dataSensors[3];

TEST test;

//
// Определим тип - указатель на член класса TEST
// (можно и без него, но запись будет сложнее)
typedef float (TEST::* MemberPointer)(void);

void setup(void) {
  Serial.begin(57600);
  while (!Serial);
}

void loop() {  
	// Определяем массив казателей на члены класса TEST can1, can2 и can3
	MemberPointer pScan[3] = { & TEST::can1,  & TEST::can2,  & TEST::can3 };
	for(int i = 0; i < 3; i++) {
		// Вызываем фкнуцию-член в контексте экземпляра как положено
		dataSensors[i] = (test.*pScan[i])();  
		Serial.print("Sensor" + String(i+1));
		Serial.print(" Value= ");
		Serial.print(dataSensors[i]);   
	} 
	Serial.println();
	delay(1000);
}

Только, вот убей Бог, не могу понять нафига Вам это! Более того, уверен, что реально-то и не нужно, просто костыль пытаетесь присобачить.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

не, не откомпилируется...что-то мне в этой конструкции тоже не нравится, визуально

А, ну да, я не заметил, у Вас же в левой части тип неправильный

rkit
Offline
Зарегистрирован: 23.11.2016

ЕвгенийП пишет:

dataSensors[i] = (test.*pScan[i])();

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

rkit пишет:

ЕвгенийП пишет:

dataSensors[i] = (test.*pScan[i])();

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

так покажите, как нужно, например как здесь

rkit
Offline
Зарегистрирован: 23.11.2016

#1

rkit
Offline
Зарегистрирован: 23.11.2016

Глянул - идиоты из ардуино вырезали <functional> для avr. Тут замена https://github.com/khoih-prog/functional-vlpp

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

rkit пишет:

Связал с экземпляром в вызывающем коде, потерял абстракцию.

Сами то поняли, что сказали?