Funktion innerhalb einer Funktion deklarieren?

Guten Morgen,

ich ueberlege gerade, wie ich meinen Code "schoen" und nachvollziehbar gestalten kann.

Problem: Ich habe mehrere aehnliche (nicht identische) sich wiederholende Codeabschnitte, welche ich nur innerhalb einer einzigen Funktion A brauche.

Ich haette diese eine Funktion A gern schoen uebersichtlich lesbar - deshalb moechte ich nicht mehrere weitere externe Funktionen schreiben (habe ich momentan so gemacht), welche dann auschliesslich von dieser Funktion A benutzt wuerden.

Nochmal: Es soll der komplette relevante Animationscode (konkret auschliesslich das Parameterhandling) in einer Funktion stehen.

Ideen, wie man das organisieren koennte?

Danke,

Helmuth

hi,

in pascal gibt es diese möglichkeit, eine funktion innerhalb einer funktion zu schreiben. die kann dann nur in dieser "enthaltenden" funktion benutzt werden...

hab' gesucht:
für c such' mal nach "nested function".

gruß stefan

Helmuth:
Ideen, wie man das organisieren koennte?

Hast Du Dir schon mal angesehen, wie Du "namespace" Namensräume zur Strukturierung Deiner Programme verwenden kannst.

Beispiel Wikipedia siehe hier

Mein Beispiel:

namespace Meine_Super_Geheimfunktionen_SetA
{
  void a()
  {}
  
  void b()
  {}

  void c()
  {}

  void d()
  {}
}

namespace Meine_Super_Geheimfunktionen_SetB
{
  void a()
  {}
  
  void b()
  {}

  void c()
  {}

  void d()
  {}
}

void animationA()
{
  using namespace Meine_Super_Geheimfunktionen_SetA;
  a();
  b();
  c();
  d();
}
 
void animationB()
{
  using namespace Meine_Super_Geheimfunktionen_SetB;
  a();
  b();
  c();
  d();
}

void setup() {
}

void loop() {
}

Vielleicht fällt Dir für Deine Anwendung ja auch irgendwas mit "namespace" zur Strukturierung ein.

Eisebaer:
hab' gesucht:
für c such' mal nach "nested function".

Es geht in C/C++ nicht.

Nested classes/verschachtelte Klassen sind aber möglich. Man könnte sich daher eine einfache Wrapper Klasse schreiben. Ein struct tut es auch. In C++ ist der einzige wirkliche Unterschied zwischen einem struct und einer Klasse, dass die Member eines structs standardmäßig public sind und die einer Klasse private.

Wenn man dann einen Functor (function object) daraus macht, kann man Objekte wie Funktionen verwenden, da die den () Operator überladen.

Visual C++ Beispiel:

class MyFunctor
{
public:
 int operator()(int x) { return calculate(x); }
private:
 int calculate(int x) { return x *= 2; }
};

int _tmain(int argc, _TCHAR* argv[])
{
 MyFunctor functor;
 cout << functor(2) << endl;
 
 getchar();
}

hi,

nie probiert, habe aber gelesen, daß es von GCC unterstützt wird.

gruß stefan

Ich bekomme da einen Fehler:
"error: a function-definition is not allowed here before '{' token"

Eine andere Option ist C++11 (geht auf dem Arduino ab 1.5.7 wenn man es in platform.txt aktiviert) und Lambda Funktionen:

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

void loop()
{
	func(3);
	delay(1000);
}

void func(int x)
{
	int variable = 5;
	
	auto sub1 = [&]() -> int
	{
		return variable *= 2;
	};

	auto sub2 = [&](int x)
	{
		Serial.println(x);
	};

	auto sub3 = []()
	{
		Serial.println("test");
	};

	Serial.println(sub1());
	sub2(x);
	sub3();
	Serial.println();
}

Damit geht es dann doch recht gut, wobei das ein ungewöhnlicher Anwendungsfall von Lamdas ist. Hat gegenüber dem Functor den Vorteil dass man kein Objekt braucht.

Das Beispiel ist etwas seltsam, aber man sieht die unterschiedliche Syntax von verschiedenen Lambdas. sub1() braucht Zugriff auf die internen Variablen. Also muss man bei den Capture Klammern das & for call-by-reference machen (wobei auch call-per-value geht, vor allem hier. Und man kann auch bestimmte Variablen angeben). -> int ist der Rückgabewert.
sub2() gibt nichts zurück, aber hat einen Parameter. sub3() hat keinen Parameter und gibt auch nichts zurück.
Eine Lambda Funktion von einer anderen Lambda Funktion aufzurufen ist auch möglich.

Ich fürchte, du hast falsch gefragt, Helmuth. Pech :wink:

Funktion innerhalb einer Funktion deklarieren?

Du willst eigentlich Klassen definieren die private Methoden kapseln, also interne Funktionen von aussen nicht störend / verwirrend in Erscheinung treten lassen ?

Dein Wunsch ist vermutlich ganz einfach das, was vor Urzeiten zur Erfindung von C++ geführt hat, als C Projekte zu unübersichtlich wurden und "objektorientiert" als Lösung gefunden wurde. Eine Einführung in Klassen, Methoden, abgeleitete Klassen und virtuelle Methoden könnte dich dazu bringen, dass du Fragen stellst, die brauchbare Tips liefern.
Alles bisher hier, selbst jurs' namespace Vorschlag, sind erst weit danach relevant.

deshalb moechte ich nicht mehrere weitere externe Funktionen schreiben (habe ich momentan so gemacht)

War aber vermutlich der richtige Weg.
Hat dich gestört, dass die Funktionen beziehungslos nebeneinander standen?
Und in ihrer Anzahl verwirrend und unübersichtlich?

Versuche, viel mehr und elementarere "Funktionen" zu schreiben, aber besser strukturiert :wink:

Dass das jetzt kein konkreter Tip ist, weiss ich auch.

Bisher sind alle Eure Antworten sehr inspirierend, Danke.

Hat dich gestört, dass die Funktionen beziehungslos nebeneinander standen?
Und in ihrer Anzahl verwirrend und unübersichtlich?

Konkretes Problem ist, dass ich ja fuer die FastLED Community How-to Beispiele schreibe. Die meisten dort haben noch deutlich weniger Ahnung vom Programmieren, als ich...

Also habe ich alle "komplizierten" Sachen (Perlin Noise, Colormapping, Palette Rules, Filter, Merging Methods, Oszillatoren, usw.) in schoene Funktionen verpackt, damit sich darum keiner mehr kuemmern muss.

Die Animation an sich besteht jetzt nur noch aus den Parametern fuer all diese Funktionen, sowie der Reihenfolge der Funktionsaufrufe - man kann da jetzt mit den Werten rumspielen und es kommt immer ein sichtbares Ergebnis raus. Einsteigerfreundlich.

Nun bin ich an dem Punkt, wo ich diese Parameter selbst auch noch dynamisch veraendere. Einen z.B. als Sinus schwingen zu lassen ist ja noch trivial.

Kompliziert wird es, wenn man nur bei speziellen Werten von definierten Parametern andere Parametersets veraendern moechte. Ab da wird es das entweder ewig lang in einer Funktion - oder man ruft eben eine externe Funktion auf, in der dann die speziellen Grenzen und Zuordnungsvorschriften drinstehen.

Da hat ein Einsteiger aber schon laengst abgewunken...

Hier mal ein Beispiel, wie das Ergebnis von solchen komplexen Abhaengigkeiten aussehen kann.

Ich will sozusagen im Idealfall ALLES relevante, alle Regler, an denen man sinnvollerweise drehen kann, in einer Funktion haben.

Beste Gruesse

Helmuth

Wenn du es als Beispiele für andere Leute und vor allem Anfänger willst, dann scheiden Lambdas wohl aus. Weil man C++11 erst extra aktivieren muss.

Aber Funktionen in Klassen oder Strukturen zu kapseln ist schon der korrekte Weg. Ein Functor macht ja auch nichts anderes. Da kommt noch etwas Syntax hinzu damit es mehr wie eine Funktion aussieht. Aber es ist immer noch ein Objekt.

Wenn dich stört dass man ein Objekt anlegen muss, könntest du auch alles als static deklarieren. Dann muss man kein Objekt anlegen. Aber dafür braucht man dann den Klassen-Namen beim Aufruf. Das geht aber nur mit einer normalen Klasse. Nicht mit einem Functor.

Ich will ALLES relevante, alle Regler, an denen man sinnvollerweise drehen kann, in einer Funktion haben.

Warum in einer Funktion ?

Das sind doch alles Eigenschaften eines Mandalas oder wie immer du dein Ding nennst.
Und das am besten aus unterlagerten Dingen (mit Eigenschaften) besteht.
Ob diese intern oder für den Benutzer zugänglich sind, ist erstmal offen.

Ob die Eigenschaften sich im Lauf der Zeit ändern, oder die Art der Änderung eine konstante Eigenschaft (höherer Ordnung sozusagen) ist, das ist die Frage nach einfach/komplex.

Dein Begriff der "Funktion" verwirrt c++ Programmierer eher, fürchte ich :wink:

Im fiktiven Beispiel-Fall besteht dann dein kompletter Sketch aus sowas wie

#include "mandalas.h"  // definiert  SuperMandala, evtl. auch SimpleMandala, KomplexMandala und noch ein paar ...
SuperMandala myMandala();

void setup() {
   myMandala.Speed=100;  // Eine statische Eigenschaft
}

void loop() {
   static unsigned long lastmillis; 
   if  ( millis() - lastmillis > 10000 )
   {
       myMandala.trigger = random(256);  // Ein Parameter, der alle 10 sec geändert wird
       lastmillis += 10000;
   }

   myMandala.go();  // die Animation
}

Klar macht es evtl. Sinn, dass dein Ding noch mehr Methoden ausser .go() kann, aber Funktionen braucht man von aussen kaum zu sehen.