std::transform mit std::stod



  • Hallo Forum,

    ich scheitere immer mal wieder daran, wenn ich einen std::algorithm mit einem "Callable" verwende und dieses Callable kein Lambda ist.

    Hier ein Beispiel zur Umwandlung von strings in doubles mittels std::stod. Wenn ich std::stod in ein Lambda verpacke, ist das kein Problem. Wenn ich versuche std::stod direkt als Callable anzugeben, scheitere ich.

    #include <algorithm>
    #include <functional>
    #include <string>
    #include <vector>
    
    int main()
    {
       std::vector<std::wstring> foo{ L"1", L"2" };
       std::vector<double> bar(2);
    
       std::transform(foo.begin(), foo.end(), bar.begin(), [](const auto& val)
       {
          return std::stod(val);
       }); // funktioniert
    
       std::transform(foo.begin(), foo.end(), bar.begin(), std::stod); // funktioniert nicht (1)
    }
    

    (1)
    error C2672: 'std::transform': no matching overloaded function found
    error C2783: '_OutIt std::transform(_InIt,_InIt,_OutIt,_Fn)': could not deduce template argument for '_Fn'

    Hat das etwas damit zu tun, dass es std::stod für strings und wstrings gibt?
    Ich habe zusätzlich versucht std::stod mit std::bind zu verwenden, aber das war eher aus der Verlegenheit heraus...

    Mir geht es hier nicht darum, ob das Beispiel grundsätzlich sinnvoll ist. Ich möchte nur verstehen, wie ich hier std::stod verwenden könnte, ohne ein Lambda zu nutzen.
    Kann mir da jemand auf die Sprünge helfen?
    Vielen Dank vorab!

    Edit: Wenn ich es richtig verstehe, scheint das mit dem default-Parameter von std::stod zusammenzuhängen. Damit wäre ein function-pointer auf std::stod ein binary_predicate und kein unary_predicate wie benötigt.
    Das bringt mich aber auch noch nicht wirklich weiter.



  • Die Signatur von std::stod passt nicht. std::stod ist definiert als double stod (const wstring& str, size_t* idx = 0);. Der zweite Parameter hat einen Default-Wert von 0, aber damit kann std::transform nicht umgehen, weil die Signatur halt nicht passt.



  • @LennyS sagte in std::transform mit std::stod:

    Hat das etwas damit zu tun, dass es std::stod für strings und wstrings gibt?

    Ja.

    @LennyS sagte in std::transform mit std::stod:

    Edit: Wenn ich es richtig verstehe, scheint das mit dem default-Parameter von std::stod zusammenzuhängen.

    Nein, damit würdest du aber auf die Nase fallen, wenn es nicht 2 Versionen der Funktion gäbe.

    Lambda ist hier leider notwendig.



  • Vielen Dank für die Hinweise!
    Es gibt also auch keine Möglichkeit mittels std::bind o.ä. den Default-Paramter "verschwinden zu lassen"? Also irgendwie so:

       std::transform(foo.begin(), foo.end(), bar.begin(), std::bind(std::stod, std::placeholders::_1, 0)); // diverse Compiler-Fehler auch hier
    

    Letzten Endes bliebe dann vermutlich ohnehin die Frage, ob die Variante mit Lambda nicht eindeutig besser lesbar ist. Ich fand halt den Ansatz nicht wirklich schön, eine Funktion (hier ein Lambda) zu implementieren, die eine andere aufruft, die das tut, was ich eigentlich möchte.



  • Ich finde std::bind jetzt auch nicht wirklich lesbar.

    Ich würde allerdings generell die Lambdadefinition aus dem transform Aufruf rausnehmen und einen sprechenden Namen verwenden:

       auto to_double = [](const auto& v ) { return stod(v); };
    
       std::transform(foo.begin(), foo.end(), bar.begin(), to_double ); 
    


  • @manni66 sagte in std::transform mit std::stod:

    Ich finde std::bind jetzt auch nicht wirklich lesbar.

    Ja, genau das meinte ich. Selbst wenn sie funktionieren würde, wäre die bind-Variante für mich schlechter lesbar als die Lambda-Variante. Habe mich umständlich ausgedrückt, sorry.
    Dein Vorschlag zum "sprechenden Namen" trägt zur Lesbarkeit bei. Das mache ich trotzdem selten, muss ich zugeben. Da begnüge ich mich meistens mit einem Kommentar.


Log in to reply