std::thread Fehler



  • Hier der betreffende Codeausschnitt:

    for (;;)
    {
    	tcp_stream handle = sock.accept();
    	clients.push_back(std::thread(&server::HTTPServer::handleClient, handle));
    }
    

    Der Fehler:

    c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1149): error C2064: Ausdruck ergibt keine Funktion, die 1 Argumente übernimmt
    1>          Klasse definiert keinen 'operator()' oder einen benutzerdefinierten Konvertierungsoperator für Zeiger auf Funktion oder Verweis auf Funktion, die die passende Argumentzahl verwenden
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1137): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>::_Do_call<,0>(std::tuple<>,std::_Arg_idx<0>)".
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1137): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>::_Do_call<,0>(std::tuple<>,std::_Arg_idx<0>)".
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\thr\xthread(195): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>::operator ()<>(void)".
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\thr\xthread(195): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>::operator ()<>(void)".
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\thr\xthread(192): Bei der Kompilierung der  Klassen-template der unsigned int std::_LaunchPad<_Target>::_Run(std::_LaunchPad<_Target> *)-Memberfunktion
    1>          with
    1>          [
    1>              _Target=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>
    1>          ]
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\thr\xthread(187): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "unsigned int std::_LaunchPad<_Target>::_Run(std::_LaunchPad<_Target> *)".
    1>          with
    1>          [
    1>              _Target=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>
    1>          ]
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\thr\xthread(205): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "std::_LaunchPad<_Target>".
    1>          with
    1>          [
    1>              _Target=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>
    1>          ]
    1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\thread(49): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void std::_Launch<std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>>(_Thrd_t *,_Target &&)".
    1>          with
    1>          [
    1>              _Target=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall server::HTTPServer::* )(tcp_stream),void,server::HTTPServer,tcp_stream>,network::socket_stream<network::tcp>>
    1>          ]
    1>          c:\users\xxx\documents\visual studio 2013\projects\webserver\webserver\httpserver.cpp(29): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "std::thread::thread<void(__thiscall server::HTTPServer::* )(tcp_stream),network::socket_stream<network::tcp>&>(_Fn &&,network::socket_stream<network::tcp> &)".
    1>          with
    1>          [
    1>              _Fn=void (__thiscall server::HTTPServer::* )(tcp_stream)
    1>          ]
    

    Kann sich das jmd. erklären?



  • Was ist server::HTTPServer::handleClient, was ist handle?



  • typedef network::socket_stream<network::tcp> tcp_stream;
    
    namespace network
    {
    	class ss_interface : public network_error
    	{
    	public:
    		template <typename socket_type>
    		friend class socket_stream;
    
    		ss_interface(SOCKET s);
    		virtual ~ss_interface();
    
    		void close();
    		virtual std::vector<char> recv() = 0;
    		virtual void send(const char *msg, std::size_t length) = 0;
    
    	private:
    		SOCKET m_sock;
    	};
    
    	template <typename protocol>
    	class socket_stream {};
    
    	template <>
    	class socket_stream<tcp> : public ss_interface
    	{
    	public:
    		socket_stream(SOCKET sock) : ss_interface(sock) {}
    
    		socket_stream(socket_stream const &rhs) : ss_interface(rhs.m_sock)
    		{
    			setError(static_cast<network::error>(rhs.error().value()));
    		}
    
    		std::vector<char> recv() override;
    		void send(const char *msg, std::size_t length) override;
    
    		socket_stream& operator=(socket_stream const&) = delete;
    	};
    }
    
    void server::HTTPServer::handleClient(tcp_stream handle)
    {
    	if (handle.fail())
    	{
    		// Error
    	}
    
    	auto buffer = handle.recv();
    }
    


  • Ich sehe weder eine Deklaration von handle noch eine von server::HTTPServer::handleClient.



  • handle ist doch einfach das typedef auf socket_stream<tcp>.

    und:

    namespace server
    {
    	class HTTPServer : public server_error
    	{
    	public:
    		void start();
    
    	private:
    		void handleClient(tcp_stream handle);
    		std::vector<std::thread> clients;
    	};
    }
    


  • thread_fails__( schrieb:

    handle ist doch einfach das typedef auf socket_stream<tcp>.

    Keine Ahnuing, du zeigst es ja nicht.

    thread_fails__( schrieb:

    namespace server
    {
    	class HTTPServer : public server_error
    	{
    	public:
    		void start();
    
    	private:
    		void handleClient(tcp_stream handle);
    		std::vector<std::thread> clients;
    	};
    }
    

    Ja, genau das war zu erwarten. Woher soll der thread einen HTTPServer nehmen, den er für den Aufruf einer nicht statischen Memberfunktion braucht? Den wirst du schon selber mit übergeben müssen.



  • Ah, natürlich, vergessen this mit zu übergeben 😑
    Aber ich hab doch gezeigt was tcp_stream bzw. handle ist im 2ten Post? Verstehe ich nicht ganz was das Problem ist ... trotzdem danke! 🙂



  • namespace network
    {
    	class ss_interface : public network_error//ein ss_interface ist ein Netzwerkfehler. 
    //Ach, nöö, gell. 
    	{
    	public:
    		template <typename socket_type>//cool
    		friend class socket_stream;//umgebrochen
    
    		ss_interface(SOCKET s);//hab immer noch keine ahnung, was 
    		virtual ~ss_interface();//ss bedeutet, kackname. 
    
    		void close();//destruktor?
    
    ...
    
    		socket_stream(socket_stream const &rhs) : ss_interface(rhs.m_sock)
    		{
    			setError(static_cast<network::error>(rhs.error().value()));//hä???
    		}
    

    Naja, bei so viel Fantasie erwarte ich ein vollständiges Minimalbeispiel, was den Fehler produziert.



  • thread_fails__( schrieb:

    Aber ich hab doch gezeigt was ... handle ist im 2ten Post?

    Nein, hast du nicht.



  • Man nehme zwei unterschiedliche Sachen, sagen wir mal TCPSocket und UDPSocket. Aber ein wenig Ähnlichkeit ist da, wenigstens im Namen, verflixt!

    Die müssen wir natürlich erstmal zusammenfassen, weil das irgendwie besser ist:

    class SocketInterface//Allein hier steckt der Wurm drin, oder? 
    
    class TCPSocket:public SocketInterface
    
    class UDPSocket:public SocketInterface
    

    So, fertig. Funktionen können beliebig SocketInterface* bekommen und ihnen ist egal, ob das nun TCP oder UDP ist.

    Fertig??? Nee, eigentlich nicht. Die Sockets sind doch zu unterschiedlich, bieten ja sogar unterschiedliche Funktionen an, man müßte ständig mit if zwischen den Typen trennen, das geht zu verbessern:

    struct tcp{};
    struct udp{};
    
    template <typename protocol>
    class socket_stream
    
    template <>
    class socket_stream<tcp>:public TCPSocket
    
    template <>
    class socket_stream<udp>:public UDPSocket
    

    und dann ist jeder Anwender genervt davon und trennt wieder.

    typedef network::socket_stream<network::tcp> tcp_stream;
    

    Viola!

    (Der Nebenwitz ist, daß man dann in Jahren kein einziges mal nen UDPSocket gebraucht hätte.)



  • manni66 schrieb:

    Nein, hast du nicht.

    Im ersten Post steht, dass handle vom Typ tcp_stream ist, im 2ten das typedef und die dazugehörige Deklaration.

    @volkard

    Zugegeben, das ich von network_error erbe ist nicht gut. Allerdings finde ich die Bedienung letzten Endes intuitiver. Man könnte natürlich auch einfach network_error als privaten Member machen und mit einer Wrapper-Funktion darauf zugreifen.

    Das ss steht für socket stream.
    Das close() für ein explizites Schließen eines Sockets, im Destruktor wird das natürlich auch gemacht. Zumindest ich brauche das manchmal.

    Der Kopierkonstruktor dürfte sich hiermit erklären:

    template <class A, class B>
    class Error
    {
    public:
    	Error()
    	{
    		setError(A::ok);
    	}
    
    	bool fail() const
    	{
    		if (ec_.value() != static_cast<int>(A::ok))
    		{
    			return true;
    		}
    		else
    		{
    			return false;
    		}
    	}
    
    	const std::error_code &error() const
    	{
    		return ec_;
    	}
    
    protected:
    	void setError(A code)
    	{
    		static B cat;
    		ec_.assign(static_cast<int>(code), cat);
    	}
    
    private:
    	std::error_code ec_;
    };
    
    namespace network
    {
    	enum class error
    	{
    		ok,
    		socket_error,
    		send_failed,
    		connect_failed,
    		accept_failed,
    		bind_failed,
    		recv_failed,
    		listen_failed
    	};
    
    	class error_category : public std::error_category
    	{
    	public:
    		const char *name() const override;
    		std::string message(int code) const override;
    	};
    
    	typedef Error<network::error, network::error_category> network_error;
    }
    

    Und deinen letzten Post kann ich nicht wirklich nachvollziehen, was willst du mir damit jetzt sagen? Ich habe bei mir einmal socket_stream, welches nur send(), recv(), close() und noch die Fehlerfunktionalität bereitstellt.

    Ansonsten habe ich u.a. noch einen socket_acceptor und socket_connector, welche mir ein socket_stream-Objekt zurückliefern. Ich fahre damit eigentlich ganz gut. Sicherlich könnte man das schöner machen, aber dazu bin ich in C++ nicht gut genug.



  • thread_fails__( schrieb:

    Der Kopierkonstruktor dürfte sich hiermit erklären:

    Nee, nicht wie er funktioniert, sondern warum Sockets kopierbar sein sollten.



  • Ich bin geade dabei einen Beispiel Multitasking Chatserver zu erweitern und habe den oben beschriebenen Fehler, komme aber mit den Erklärunge hier nicht weiter.
    Ich habe jetzt schon Stundenlang gesucht und nichts anderes zu diesem Thema als diesen Thread gefunden.

    Hier der Quelltext:
    C_chatserver.cpp

    #include "H_C_chatserver.h"
    #include <thread>
    using namespace std;
    
    int C_chatserver::InitWinSock(){
    	int Val = 0;
    	WSAData wsaDATA;
    	WORD DllVersion = MAKEWORD(2, 1);
    	Val = WSAStartup(DllVersion, &wsaDATA);
    	return Val;
    }
    int C_chatserver::ServerThread(int ID){
    	char* Buffer = new char[256];
    	int size = 0;
    	while (true){
    		ZeroMemory(Buffer, 512);
    		if ((size = recv(Connections[ID], Buffer, 256, NULL)) > 0){
    
    			for (int a = 0; a < Counter; a++){
    				if (Connections[a] == Connections[ID]){
    					cout << Buffer << endl;
    				}
    				else{
    					send(Connections[a], Buffer, 256, NULL);
    				}
    			}
    		}
    	}
    	return 10;
    }
    C_chatserver::C_chatserver(string ip,int port){
    	system("color 0a");
    
    	int Val = InitWinSock();
    	if (Val != 0){
    		MessageBoxA(NULL, "WINSOCK STARTUP ERROR!!!", "Error", MB_OK | MB_ICONERROR);
    		exit(1);
    	}
    
    	Connections = (SOCKET*)calloc(64, sizeof(SOCKET));
    
    	sListen = socket(AF_INET, SOCK_STREAM, NULL);
    	sConnect = socket(AF_INET, SOCK_STREAM, NULL);
    
    	addr.sin_addr.s_addr = inet_addr(ip.c_str());
    	addr.sin_port = htons(port);
    	addr.sin_family = AF_INET;
    
    	bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
    	listen(sListen, 64);
    	cout << "Server started" << endl<<"Port: "<<port<<endl<<"IP: " << ip.c_str()<< endl;
    	while (true){
    		if (sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen)){
    			Connections[Counter] = sConnect;
    			char *Name = new char[64];
    			ZeroMemory(Name, 64);
    			sprintf(Name, "%i", Counter);
    			send(Connections[Counter], Name, 64, NULL);
    			send(Connections[Counter], "Welcome", 64, NULL);
    
    			cout << "New Connection" << endl;
    			thread t1(&C_chatserver::ServerThread, Counter);
    			Counter++;
    		}
    		Sleep(50);
    	}
    }
    

    H_C_chatserver.h

    #include <WinSock.h>
    #include <iostream>
    #include <Windows.h>
    
    using namespace std;
    
    #pragma comment (lib, "ws2_32.lib")
    
    class C_chatserver{
    public:
    	C_chatserver(string,int);
    private:
    	SOCKADDR_IN addr;
    	int addrlen = sizeof(addr);
    	int Counter;
    	SOCKET sConnect;
    	SOCKET sListen;
    	SOCKET *Connections;
    
    	int InitWinSock();
    	int ServerThread(int ID);
    
    };
    

    Schon im Voraus vielen Dank für eure Hilfe!


Anmelden zum Antworten