qualified-id in declaration before '(' token



  • Erst mal vielen Dank für eure Hinweise!

    • Ich verwende exakt die verlinkte Datei, ja.
    • Das Programm XCSoar ist ein Teil des Projektes OpenVario (https://github.com/Openvario/meta-openvario). Ich kompiliere das komplette Image, wie es dort beschrieben ist.
    • Ja, ich setzte eine Funktion in eine Funktion. Ich nahm an, das ein pures hintereinander setzen nicht funktionieren kann:
    void
    ScreenRotationWidget::SaveRotation(string &rotation, 
                                         string &rotationvalue){
           File::WriteExisting(Path("/boot/config.uEnv"), rotation);
           File::WriteExisting(Path("/sys/class/graphics/fbcon/rotate_all"), rotationvalue);
    
    void
    ScreenRotationWidget::Prepare([[maybe_unused]] ContainerWindow &parent,
                                  [[maybe_unused]] const PixelRect &rc) noexcept
    {
      AddButton("Landscape", [](){
        SaveRotation("rotation=0", "0");
        static constexpr const char *argv[] = {
          "/bin/sh", "-c", 
          "echo The screen was rotated to landscape", 
          nullptr 
        };
    
        RunProcessDialog(UIGlobals::GetMainWindow(),
                         UIGlobals::GetDialogLook(),
                         "Landscape", argv);
      });
      
    }
    


  • @Blaubart sagte in qualified-id in declaration before '(' token:

    Gut.

    • Ja, ich setzte eine Funktion in eine Funktion. Ich nahm an, das ein pures hintereinander setzen nicht funktionieren kann (warm wird das hier nicht korrekt als Code angezeigt??):

    void [...]

    Formatierten Code kannst du hier im Forum erzeugen, indem du auf den </>-Button im Editor drückst. Der Code muss am Anfang und Ende mit je 3 Backticks eingerahmt werden (``` bzw. ```cppfür C++-Syntax Highligthing).

    Ich hab deinen geposteten Code mal so korrigiert, dass er (hoffentlich) kompiliert (Einrückung von mir):

    void
    ScreenRotationWidget::SaveRotation(string &rotation, string &rotationvalue)
    {
        File::WriteExisting(Path("/boot/config.uEnv"), rotation);
        File::WriteExisting(
            Path("/sys/class/graphics/fbcon/rotate_all"),
            rotationvalue
        );
    } // <--- Schliessende geschweifte Klammer am Funktionsende.
    
    void
    ScreenRotationWidget::Prepare(
        [[maybe_unused]] ContainerWindow &parent,
        [[maybe_unused]] const PixelRect &rc
    ) noexcept
    {
        AddButton(
            "Landscape",
            []() // <--- Lambda-Funktion, die muss in ihrer einfachsten Form mit []() eingeleitet werden.
            {
                SaveRotation("rotation=0", "0");
                static constexpr const char *argv[] = {
                    "/bin/sh", "-c",
                    "echo The screen was rotated to landscape",
                    nullptr
                };
                RunProcessDialog(
                    UIGlobals::GetMainWindow(),
                    UIGlobals::GetDialogLook(),
                    "Landscape",
                    argv
                );
            }
            // Falls dir das mit der Lambda-Funktion nicht ganz klar sein sollte:
            // Der Code in dieser Funktion wird nicht hier direkt ausgeführt, sondern
            // es wird damit ein Funktionsobjekt erzeugt, dass als zweites Argument an
            // die Funktion AddButton(name, funktion) übergeben wird. Diese Lambda-Funktion
            // wird dann irgendwann später vom GUI-Code aufgerufen - z.B. wenn man auf den 
            // Button drückt :-) ... die Prepare()-Funktionen dienen wahrscheinlich nur dazu, 
            // die GUI einmalig zu initialisieren, bevor diese angezeigt wird.
        );
    }
    

    Das macht jetzt erstmal nur syntaktisch Sinn, zur Korrektheit kann ich nichts sagen - sieht aber oberflächlich nicht verkehrt aus, falls Funktionen wie File::WriteExisting das richtige tun und die Pfade stimmen.



  • Um zu testen ob das ganze mit String so funktionieren könnte, hatte ich folgendes am Anfang getestet:

    File::WriteExisting(Path("/boot/config.uEnv"), "rotation=0");
    

    Nun kommt beim Kompilieren ein Fehler, der meiner Meinung nach sagt, dass String nicht geeignet ist.

    | src/OV/OpenVarioMenu.cpp:181:52: error: cannot convert 'std::string' {aka 'std::__cxx11::basic_string<char>'} to 'const char*'
    |   181 |     File::WriteExisting(Path("/boot/config.uEnv"), rotation);
    |       |                                                    ^~~~~~~~
    |       |                                                    |
    |       |                                                    std::string {aka std::__cxx11::basic_string<char>}
    




  • ich denke, ich komme der Lösung näher 😉
    Dieser Code kompiliert.

    void
    ScreenRotationWidget::SaveRotation(string &rotation, string &rotationvalue)
    {
        File::WriteExisting(Path("/boot/config.uEnv"), (rotation).c_str());
        File::WriteExisting(Path("/sys/class/graphics/fbcon/rotate_all"), (rotationvalue).c_str());
    }
    

    und dieser hier macht noch Stress:

      AddButton("Landscape", [](){
        SaveRotation("rotation=0", "0");
        static constexpr const char *argv[] = {
          "/bin/sh", "-c", 
          "echo The screen was rotated to landscape", 
          nullptr 
        };
    
        RunProcessDialog(UIGlobals::GetMainWindow(),
                         UIGlobals::GetDialogLook(),
                         "Landscape", argv);
      });
    
    | src/OV/OpenVarioMenu.cpp: In lambda function:
    | src/OV/OpenVarioMenu.cpp:190:17: error: 'this' was not captured for this lambda function
    |   190 |     SaveRotation("rotation=0", "0");
    |       |     ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
    | src/OV/OpenVarioMenu.cpp:190:17: error: cannot call member function 'void ScreenRotationWidget::SaveRotation(std::string&, std::string&)' without object
    


  • @Blaubart sagte in qualified-id in declaration before '(' token:

    und dieser hier macht noch Stress:

      AddButton("Landscape", [](){
        SaveRotation("rotation=0", "0");
        static constexpr const char *argv[] = {
          "/bin/sh", "-c", 
          "echo The screen was rotated to landscape", 
          nullptr 
        };
    
        RunProcessDialog(UIGlobals::GetMainWindow(),
                         UIGlobals::GetDialogLook(),
                         "Landscape", argv);
      });
    
    | src/OV/OpenVarioMenu.cpp: In lambda function:
    | src/OV/OpenVarioMenu.cpp:190:17: error: 'this' was not captured for this lambda function
    |   190 |     SaveRotation("rotation=0", "0");
    |       |     ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
    | src/OV/OpenVarioMenu.cpp:190:17: error: cannot call member function 'void ScreenRotationWidget::SaveRotation(std::string&, std::string&)' without object
    

    Versuch mal

      AddButton("Landscape", [this](){
    


  • geht leider so nicht:

    | src/OV/OpenVarioMenu.cpp: In lambda function:
    | src/OV/OpenVarioMenu.cpp:190:18: error: cannot bind non-const lvalue reference of type 'std::string&' {aka 'std::__cxx11::basic_string<char>&'} to an rvalue of type 'std::string' {aka 'std::__cxx11::basic_string<char>'}
    |   190 |     SaveRotation("rotation=0", "0");
    |       |                  ^~~~~~~~~~~~
    | In file included from ../recipe-sysroot/usr/include/c++/11.3.0/string:55,
    |                  from ../recipe-sysroot/usr/include/c++/11.3.0/bits/locale_classes.h:40,
    |                  from ../recipe-sysroot/usr/include/c++/11.3.0/bits/ios_base.h:41,
    |                  from ../recipe-sysroot/usr/include/c++/11.3.0/streambuf:41,
    |                  from ../recipe-sysroot/usr/include/c++/11.3.0/bits/streambuf_iterator.h:35,
    |                  from ../recipe-sysroot/usr/include/c++/11.3.0/iterator:66,
    |                  from ./output/src/boost_1_81_0/boost/move/detail/iterator_traits.hpp:27,
    |                  from ./output/src/boost_1_81_0/boost/move/detail/reverse_iterator.hpp:25,
    |                  from ./output/src/boost_1_81_0/boost/intrusive/detail/reverse_iterator.hpp:16,
    |                  from ./output/src/boost_1_81_0/boost/intrusive/list.hpp:28,
    |                  from ./src/ui/window/custom/WList.hpp:28,
    |                  from ./src/ui/window/ContainerWindow.hpp:29,
    |                  from ./src/Form/Form.hpp:26,
    |                  from ./src/Dialogs/WidgetDialog.hpp:26,
    |                  from src/OV/OpenVarioMenu.cpp:26:
    | ../recipe-sysroot/usr/include/c++/11.3.0/bits/basic_string.h:533:7: note:   after user-defined conversion: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with <template-parameter-2-1> = std::allocator<char>; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
    |   533 |       basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
    |       |       ^~~~~~~~~~~~
    | src/OV/OpenVarioMenu.cpp:179:44: note:   initializing argument 1 of 'void ScreenRotationWidget::SaveRotation(std::string&, std::string&)'
    |   179 | ScreenRotationWidget::SaveRotation(string &rotation, string &rotationvalue)
    |       |      
    


  • es funktioniert

    void
    ScreenRotationWidget::SaveRotation(const string &rotation, const string &rotationvalue) <--hier const eingefügt
    {
        File::WriteExisting(Path("/boot/config.uEnv"), (rotation).c_str());
        File::WriteExisting(Path("/sys/class/graphics/fbcon/rotate_all"), (rotationvalue).c_str());
    }
    
    {
      AddButton("Landscape", [&](){  <--hier [&] statt []
        SaveRotation("rotation=0", "0");
        static constexpr const char *argv[] = {
          "/bin/sh", "-c", 
          "echo The screen was rotated to landscape", 
          nullptr 
        };
    
        RunProcessDialog(UIGlobals::GetMainWindow(),
                         UIGlobals::GetDialogLook(),
                         "Landscape", argv);
      });
    
    

    Danke allen für die Hilfe!!!



  • geht leider so nicht: (...)

    Ja, das ist halt jetzt ein anderer, zusätzlicher Fehler.

    es funktioniert (...)

    [&] ist Overkill, [this] wie ich geschrieben habe sollte reichen.



  • Wie so oft ist ein Problem nicht so trivial, wie es zu Beginn scheint. Das obige Funktioniert, hat aber den Nachteil, dass der String immer in die erste Zeile der Datei geschrieben wird. Meine Datei hat in etwa folgenden Inhalt:

    rotation=1
    timeout=10
    LANG=de_DE.UTF-8

    Ich muss es daher noch realisieren, dass der String in die Zeile geschrieben wird, in der der alte String stand. Sollte der String noch nicht vorhandene ein, soll er hinten angehängt werden. Ich habe den Hinweis bekommen, dass das mit folgendem Skript geht:
    https://github.com/XCSoar/XCSoar/blob/f829b8f394d2eb21c276d17f38b134bc3f9e7466/src/Profile/File.cpp

    Ich habe mir andere Dateien angeschaut, in denen Profile::LoadFile vorkommt, verstehe aber die Funktionsweise noch nicht. Nach meinem Verständnis muss ich ja den zu suchenden String und den Pfad angeben. Daher habe ich mir was in der Art gedacht:
    Profile::LoadFile("LANG*", "/boot/config.uEnv");

    Nach dem ich mir die Beispiel angeschaut habe bin ich mir ziemlich sicher, das it Blödsinn. Vielleicht kann mir jemand helfen die Funktion besser zu Verstehen.

    Danke!!



  • Man lädt einmalig die Datei mit LoadFile und übergibt eine leere ProfileMap.
    Anschließend ändert man die Werte in der ProfileMap und speichert dann mit SaveFile wieder die gesamte Datei ab (man kann in einer Textdatei nicht direkt einzelne Zeilen ersetzen).



  • @hustbaer Danke, ändere ich!!



  • @Th69 Danke!! Das hilft für das Verständnis sehr weiter!!!



  • Ich versuche mich gerade in das Thema ProfileMap einzuarbeiten. Ich versuche mal kleinschrittige Fragen zu stellen, um es besser verstehen zu können.

    Die Funktion LoadConfig müsste also ein map mit dem Namen configuration anlegen und jede Zeile der Datei /boot/config.uEnv auslesen. Dann wird z.B. dem key1 rotation und als Wert 1, dem key3 LANG und als Wert de_DE.UTF-8, etc zugewiesen. Habe ich das bis hierher korrekt verstanden?

    static void LoadConfig()
    {
        Profile::Clear();
        Profile::LoadFile(configuration, "/boot/config.uEnv");
    }
    

    Aufgerufen wird die Funktion mit:

    LoadConfig();
    


  • Ja, du mußt eine Variable dafür anlegen:

    ProfileMap configuration;
    

    und dann kannst du (entsprechend Map.hpp) eine der Set-Funktionen dafür aufrufen, z.B.

    configuration.Set("rotation", 1);
    


  • Ich hoffe, ich hab es korrekt verstanden. Dann müsste die Funktion so aussehen:

    static void LoadConfig(&keyvalue, &value)
    {
        ProfileMap configuration;
        Profile::Clear();
        Profile::LoadFile(configuration, "/boot/config.uEnv");
        configuration.Set(keyvalue, value);
    }
    

    Und die Funktion müsste dann so aufgerufen werden, oder?

    LoadConfig("rotation", 1);
    


  • Fast - du mußt noch die richtigen Typen bei den Funktionsparametern angeben (C++ ist typsicher).
    Und & ist nur bei Referenzparametern anzugeben.

    Und ich würde die Funktion ' ChangeConfig' nennen und noch den 'Profile::SaveFile(...)'-Aufruf hinzufügen (sonst macht die Funktion bisher nichts wirklich sinnvolles).

    PS: Wenn du verschiedene Typen für value benötigst (und nicht nur int), dann brauchst du hier schon fortgeschrittenere C++-Funktionalität: template.



  • Vielen Dank für deine geduldige Erklärung!!

    Ich habe die Funktion soweit angepasst:

    static void ChangeConfig(const sting keyvalue, const sting value)
    {
        ProfileMap configuration;
        Profile::Clear();
        Profile::ChangeConfig(configuration, "/boot/config.uEnv");
        configuration.Set(keyvalue, value);
        Profile::SaveFile(configuration, "/boot/config.uEnv");
    }
    

    Der Aufruf erfolgt mit:

    ChangeConfig("rotation", 1);
    

    Der Teil müsste so nun funktionieren, oder?

    Tatsächlich wird es auch einen Aufruf in der Art geben müssen:

    ChangeConfig("LANG", "de_DE.UTF-8");
    

    Das heißt, wenn ich dich richtig verstehe, dass das so noch nicht geht?



  • Kompilieren bringt noch Fehler:

    | src/OV/OpenVarioMenu.cpp:98:16: error: aggregate 'ProfileMap configuration' has incomplete type and cannot be defined
    |    98 |     ProfileMap configuration;
    |       |                ^~~~~~~~~~~~~
    | src/OV/OpenVarioMenu.cpp:99:14: error: 'Clear' is not a member of 'Profile'
    |    99 |     Profile::Clear();
    |       |              ^~~~~
    | src/OV/OpenVarioMenu.cpp:100:14: error: 'ChangeConfig' is not a member of 'Profile'; did you mean 'ChangeConfig'?
    |   100 |     Profile::ChangeConfig(configuration, "/boot/config.uEnv");
    |       |              ^~~~~~~~~~~~
    | src/OV/OpenVarioMenu.cpp:96:13: note: 'ChangeConfig' declared here
    |    96 | static void ChangeConfig(const string keyvalue, const string value)
    |       |             ^~~~~~~~~~~~
    | make: *** [build/compile.mk:107: output/UNIX/opt/src/OV/OpenVarioMenu.o] Error 1
    


  • Sorry, aber so wird das nichts - du mußt schon die Grundlagen (Syntax und Semantik) von C++ verstehen.

    Am besten (wenn du englisch kannst) mittels LearnCpp.
    Es gibt auch noch (für den Einstieg) Wiki: C++ Programmierung.
    Sonst s.a. noch Linkliste.

    Ich gebe dir jetzt (einmalig) mal den Code:

    #include "Map.hpp" // für ProfileMap
    
    static void ChangeConfig(const string &keyvalue, int value)
    {
        const char * const ConfigPath = "/boot/config.uEnv"; // um nur eine Codestelle dafür zu haben
    
        ProfileMap configuration;
        // Profile::Clear(); // <- diese Funktion gibt es wohl nicht bei XCSoar
        Profile::LoadFile(configuration, ConfigPath); // Funktionsname wieder zurück geändert
        configuration.Set(keyvalue, value);
        Profile::SaveFile(configuration, ConfigPath);
    }
    

    Für andere Aufrufe (z.B. string) bräuchtest du, wie schon geschrieben, ein Template:

    template<typename T>
    static void ChangeConfig(const string &keyvalue, T value)
    {
      // der Rest bleibt gleich
    }
    

Anmelden zum Antworten