Hilfe: Funktion in einer Timer-Klasse (void) soll einen Wert zurückgeben (C4716)
-
Hallo,
ich möchte die Funktion Berechne() (ohne Rückgabewert) alle 500ms ausführen, allerdings kommt der folgende Fehler
C4716 Timer::Berechne Muss einen Wert zurückgeben Timer.cpp Zeile 28
Wo ist das Problem?
Code Timer.h#ifndef TIMER_H #define TIMER_H #include <chrono> #include <functional> #include <thread> class Timer { public: Timer(); ~Timer(); private: void timer_start(std::function<void()> func, int interval); std::function<void()> Berechne(); private: int timer; }; #endif
Timer.cpp
#include "Timer.h" #include <sstream> #include <string> Timer::Timer() { timer = 0; timer_start(Berechne(), 500); } Timer::~Timer() {} void Timer::timer_start(std::function<void()> func, int interval) { std::thread([func, interval]() { while (true) { func(); std::this_thread::sleep_for(std::chrono::milliseconds(interval)); } }).detach(); } std::function<void()> Timer::Berechne() { //DoSomething }
-
@stefanpc81 sagte in Hilfe: Funktion in einer Timer-Klasse (void) soll einen Wert zurückgeben (C4716):
Hallo,
ich möchte die Funktion Berechne() (ohne Rückgabewert) alle 500ms ausführen, allerdings kommt der folgende Fehler
C4716 Timer::Berechne Muss einen Wert zurückgeben Timer.cpp Zeile 28
Wo ist das Problem?Hier:
std::function<void()> Berechne();
-
Lese die Fehlermeldung. Wie wird aus einer Funktion bzw. Methode ein Wert zurückgegeben? Zauberwort: return ...;
-
@Belli sagte in Hilfe: Funktion in einer Timer-Klasse (void) soll einen Wert zurückgeben (C4716):
std::function<void()>
Sorry, ich stehe auf dem Schlauch... Ich bin noch relativ neu dabei, zu programmieren. Da die Funktion void ist, gibt es doch kein return ... Und return std::function<void()>; funktioniert auch nicht.
-
@stefanpc81
Die Funktion ist nicht void - sie ist std::function<void()>std::function<void()> Berechne(); //nicht void void Berechne(); //void
-
Und bei
timer_start(Berechne(), 500);
möchtest du nur die Funktion übergeben und nicht die Funktion direkt ausführen, also
timer_start(Berechne, 500);
Wahrscheinlich hast du dann wegen der Fehlermeldung den Rückgabetyp fälschlicherweise geändert...
-
Hallo,
danke soweit für die Hilfen. Ich weiß nicht, ob ich eure Lösungsvorschläge richtig verstanden habe:- Sowie ich die Erklärung im Web verstanden habe, bedeutet die Verwendung von std::function<void()> dass die Funktion vom Typ void sein muss. Also muss ich folglich wie von @Belli void Berechne(); schreiben.
- @Th69 Die () im Konstruktor weglassen, da diese zu übergebende Funktion unter void Timer::timer_start(...) ausgeführt wird.
- Trotzdem kommen noch zwei Fehlermeldungen:
C4716 Timer::Berechne Muss einen Wert zurückgeben Timer.cpp Zeile 28
Leider immer noch. Ich konnte auch im Web keinen Rückgabetyp mit der Verwendung std::function<void()> finden bzw. wie gesagt: mit void gibt es doch gar kein return ... Ich verstehe nach wie vor nicht, was ich hier konkret schreiben soll. - Die zweite Fehlermdlung besagt
E0415 Für eine Konvertierung von ""void ()"" in""std::function<void ()>"" ist kein passender Konstruktor vorhanden. Timer.cpp Zeile 8
Ich habe jetzt 1,5 Stunden herumprobiert bzw. nichts im Web gefunden, was mir weiterhelfen könnte.
-
Dein
Timer::Berechne
gibt angeblich laut Signatur eine Funktion zurück, die 0 Parameter hat und nichts returnt. Gesucht ist aber eine Funktion, die nichts returnt und NICHT eine Funktion, die eine Funktion zurückgibt, die die passenden Eigenschaften hat. (*)Also nochmal:
der Funktionvoid timer_start(std::function<void()> func, int interval);
musst du 2 Parameter übergeben: ein ausführbares Ding mit 0 Parametern und mit void als Rückgabetyp sowie einenint
.Du übergibst
Berechne()
, d.h. das, was die FunktionBerechne
zurückgibt. In der Funktion befindet sich aber keinreturn
. Was du stattdessen willst: die Funktionstd::function<void()> Berechne()
solltevoid Berechne()
sein - und dann übergibst duBerechne
(die Funktion selbst) stattBerechne()
(das Ergebnis der Funktion).Aber Achtung: dein Berechne ist eine Memberfunktion. Sie nimmt implizit einen this-Pointer als Argument. Du kannst also
Berechne
nicht übergeben, wenn die Fkt nicht static ist. Daher musst du den this-Pointer an die Funktion binden. Entweder mitbind
oder indem du ein Lambda machst:timer_start([this](){ this->Berechne(); }, 500);
Noch was Allgemeines zu deinem Code: Es bleibt noch eine andere Frage: wieso ist "Berechne" eine Member-Funktion des Timers?! Ein Timer sollte nur Timer-Dinge tun. Die Funktion Berechne sollte daher anderswo zu finden sein. Ein Timer sollte mit beliebigen Funktionen umgehen können.
PS: (*) std::function macht type erasure und du kannst auch andere, kompatible Funktionen übergeben und insbesondere auch solche mit einem Returnwert. Aber das soll dich erstmal nicht interessieren.
-
Die Lösung mit bind müsste so aussehen:
#ifndef TIMER_H #define TIMER_H #include <chrono> #include <functional> #include <thread> class Timer { public: Timer(); ~Timer(); private: void timer_start(std::function<void()> func, int interval); void Berechne(); private: int timer; }; #endif
#include "Timer.h" #include <sstream> #include <string> Timer::Timer() { timer = 0; std::function<void()> f = std::bind(&Timer::Berechne, this); timer_start(f, 500); } Timer::~Timer() {} void Timer::timer_start(std::function<void()> func, int interval) { std::thread([func, interval]() { while (true) { func(); std::this_thread::sleep_for(std::chrono::milliseconds(interval)); } }).detach(); } void Timer::Berechne() { //DoSomething }
-
Also irgendwie ist das schon eine recht komische Timer Implementierung. Es wird eine Klasse verwendet, aber kein RAII und deswegen wohl auch das thread.detach(). Entkoppelte Threads sind in der Regel immer "böse", sollte man einfach nicht machen. Falls du C++17 verwenden kannst, kann man daraus ein recht brauchbares Template machen. So spontan hätte ich mir den Timer so gebastelt, wenn ich keine großen Anforderungen habe.
#include <chrono> #include <functional> #include <iostream> #include <thread> template <bool Async = true, bool Joinable = true> struct Timer { template <typename Callable, typename... Args> Timer(const size_t wait_ms, Callable &&func, Args &&...args) { auto task(std::bind(std::forward<Callable>(func), std::forward<Args>(args)...)); if constexpr (Async) { _thread = std::thread([wait_ms, task]() { std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms)); task(); }); if constexpr (!Joinable) _thread.detach(); } else { std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms)); task(); } } ~Timer() { if (Joinable && _thread.joinable()) _thread.join(); } std::thread _thread; };
Und dieses Timer Template kann man dann so benutzen:
void test(const char *arg) { std::cout << arg << std::endl; } int32_t main() { Timer timer1(2000, test, "timer1"); Timer timer2(1000, test, "timer2"); return 0; }
Dieses einfache Template unterstützt keine Rückgabewerte. Man kann aber das Template nehmen und statt alles im Constructor zu machen, schiebt man einfach alles zum Beispiel in den function call operator (
operator()
). Dann muss man sich noch aus einem Promise/Future einen Rückgabewert-Container basteln und tataaa, man kann sich auch Rückgabewerte geben lassen. Wenn man es noch etwas bunter will, kann man auch mit condition variables das Ganze abbrechbar machen (sleep_for
durchcondition_variable::wait_for
Konstruktion ersetzen).