qualified-id in declaration before '(' token



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

    Ich versuche ein C++-Skript zu erweitern: (https://github.com/freevariode/XCSoar/blob/master/src/OV/OpenVarioMenu.cpp)

    Im Moment arbeite ich daran mit einer Funktion (SaveRotation) Einträge in einer Datei zu ändern. Beim Kompilieren bekomme ich aber immer den unten stehenden Error. Was mache ich falsch?

    OpenVarioMenu.cpp:183:37: error: qualified-id in declaration before '(' token
    | 183 | ScreenRotationWidget::SaveRotation(string &rotation, &rotationvalue){

    1. Ist es exakt die von dir verlinkte Datei, die das Problem verursacht, oder hast du da Änderungen gemacht? Wenn ja, dann bitte deine Änderungen hier posten.

    2. Verwendest du die Build-Skripte des Projekts um das zu kompileren? In diesem Fall sind das die Makefiles im Wurzelverzeichnis des Projekts (https://github.com/freevariode/XCSoar/blob/master/Makefile und das ganze Zeug in https://github.com/freevariode/XCSoar/tree/master/build). Also kompilierst du mittels make <optionen> im Wurzelverzeichnis? Das Projekt ist hinreichend komplex, dass es durchaus auch zu Fehlern führen kann, wenn man das Build-System nicht verwendet und die Datei direkt kompiliert. Siehe dazu auch Compiling XCSoar ff. im Developer's Manual des Projekts. Du solltest das Projekt erstmal ohne jegliche Änderungen erfolgreich kompilieren, wie es da steht und erst dann eigene Ändewrungen vornehmen.

    Es würde helfen wenn du beschreibst, wie du genau vorgegangen bist, als es zu dieser Fehlermeldung kam.



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

    Du scheinst dort irgendwie eine Funktion in einer Funktion haben zu wollen - bist du in ScreenRotationWidget::Prepare oder in ScreenRotationWidget::SaveRotation?

    Ja stimmt, das hier sieht etwas komisch aus und wird so nicht funktionieren - zumal es auch noch eine Member-Fuktion ist, die auf jeden Fall eine Ebene höher gehört:

    ScreenRotationWidget::Prepare([[maybe_unused]] ContainerWindow &parent,
                                  [[maybe_unused]] const PixelRect &rc) noexcept
    {
      void
      ScreenRotationWidget::SaveRotation(string &rotation, 
                                         string &rotationvalue){
           File::WriteExisting(Path("/boot/config.uEnv"), rotation);
           File::WriteExisting(Path("/sys/class/graphics/fbcon/rotate_all"), rotationvalue);
      {
      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);
      });
     ...
    }
    

    "Funktion in Funktion" geht nicht auf diese Weise, sondern nur mit Lambdas, wie z.B. beim zweiten Argument von AddButton.



  • 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?


Anmelden zum Antworten