Register for your free account! | Forgot your password?

Go Back   elitepvpers > Coders Den > C/C++
You last visited: Today at 11:00

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



std::function of a function returning an std::function

Discussion on std::function of a function returning an std::function within the C/C++ forum part of the Coders Den category.

Reply
 
Old   #1


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,395
std::function of a function returning an std::function

Nun muss ich nach langer Zeit auch mal wieder einen Thread erstellen, weil mir Google nicht mehr weiterhelfen kann.

Ich verzweifle an Folgendem Vorhaben:

Code:
#include <Windows.h>
#include <string>
#include <iostream>

using namespace std;

typedef std::function<void ()> func;

struct testclass
{
	std::function<func ()> member;

	operator func() 
	{
		return member();
	}
	func get()
	{
		return member();
	}
};

int main()
{
	func f = []() { cout << "test"; };
	testclass obj;
	obj.member = [&]() { return f; };
	func test = obj;  //<- causes error
              test = (std::function<void ()>)obj;  //<- causes error
              test = obj.get();  //<-works
              test = obj.operator func();  //<- works
	test();
         return 0;
}
Der Compiler verweigert seinen Dienst mit:
Quote:
Fehler 1 error C2064: Ausdruck ergibt keine Funktion, die 0 Argumente übernimmt c:\program files\microsoft visual studio 11.0\vc\include\xrefwrap 431 1 CSharpAttributes
Wie man sehen kann: Der explizite Aufruf des Operators oder von get() funktioniert. Implizit verursacht es oben genannten völlig unverständlichen Fehler.

Build output:
Was übersehe ich?
MrSm!th is offline  
Old 11/09/2013, 19:34   #2
 
elite*gold: 0
Join Date: Aug 2012
Posts: 236
Received Thanks: 94
std::function hat zwei Konstruktoren function<Func>(Func&&) und function<Func>(const Func&). Die werden aufgerufen.
Tasiro is offline  
Old 11/09/2013, 20:03   #3


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,395
Und inwiefern soll das bei expliziter Verwendung der Funktion anders sein?
Außerdem würde das doch eine Fehlermeldung von zu vielen möglichen Überladungen erzeugen und keine von zu wenig.
MrSm!th is offline  
Old 11/09/2013, 20:41   #4
 
elite*gold: 0
Join Date: Aug 2012
Posts: 236
Received Thanks: 94
Wo Microsofts Compiler den function-Konstruktor verwenden kann, tut er das. Nur kann das testclass-Objekt nicht als Funktionsobjekt genutzt werden. Das sagt der Compiler nicht immer direkt.
Explizit rufst du die Funktion nur einmal auf (wenn du mit Funktion den Konvertierungsoperator meinst).

functional sollte noch eingebunden werden.


func test = obj;
Das wird zu:
func test = func (obj);

test = (func) obj;
Das wird zu:
test = func (obj);
Tasiro is offline  
Old 11/10/2013, 00:34   #5


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,395
Ja, aber sollte der Konstruktor nicht dennoch funktionieren, weil testclass implizit in function konvertiert wird?
Und get() macht doch prinzipiell dasselbe.

Der Header wird eingebunden, hab ich nur in dem Sample vergessen.

edit:

Ok, ich glaub, ich habs kapiert. Es gibt auch einen parametrisierten Konstruktor, der noch einen weiteren Typ annimmt, um Functors zu unterstützen und dementsprechend wird bei der direkten Zuweisung mein testclass Objekt als Functor interpretiert (was scheitert, weil er keinen operator() hat). Beim expliziten Aufruf passiert das nicht, weil std::function da gar nicht mit testclass in Verbindung kommt, sondern direkt die Funktion zurückgegeben wird - bei der Zuweisung aber schon und die implizite Konvertierung wird gar nicht erst in Erwägung gezogen.
Was mich wundert: Wieso diese Fehlermeldung? Dürfte die nicht erst kommen, wenn ich das function Objekt aufrufe und deshalb der nicht vorhandene operator() den Aufruf fehlschlagen lässt?
Der Fehler kommt auch, wenn ich den Aufruf auskommentiere. Wieso wird denn der Aufruf schon im Konstruktor ausgewertet?

Die nächste Frage wäre, ob und wie ich das irgendwie umgehen kann, dass mein Objekt als Functor interpretiert wird, ohne die Verwendung zu ändern (sprich: die Zuweisung soll implizit funktionieren).
MrSm!th is offline  
Old 11/10/2013, 11:26   #6
 
elite*gold: 0
Join Date: Aug 2012
Posts: 236
Received Thanks: 94
Nein, sollte er nicht. Vor einem Aufruf wird nicht erst noch konvertiert. Entweder ist eni entsprechender Operator vorhanden, oder nicht.
GCC ruft bei func test = obj den Konvertierungsoperator auf und kompiliert es.
Tasiro is offline  
Old 11/10/2013, 11:31   #7


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,395
Vielen Dank Microsoft..
Wie schon gesagt, eine Idee wie ich das fixen könnte?


Btw. Natürlich würde konvertiert, wenn es nur inkompatible Konstruktoren gäbe, aber das übergebene Objekt implizit in das Argument konvertierbar wäre. Das Problem ist doch, dass eben nicht die von dir oben genannten Konstruktoren aufgerufen werden (das gäbe auch eine andere Fehlermeldung, nämlich irgendwas mit Mehrdeutigkeit), sondern dass der Konstruktor für Functors aufgerufen wird, also jener, der noch einen weiteren Typparameter _Fx hat, der in diesem Fall testclass wäre. Problem ist dabei natürlich, dass das Objekt keinen operator() hat. Wäre irgendwie sinnvoll, wenn std::function den Functor Konstruktor mit enable_if nur anbieten würde, wenn das Objekt callbar ist :/

Was ich mich nun frage: Welcher Compiler hat Recht? Hat eine Template-Funktion Vorrang vor einer normalen, deren Signatur nicht ganz passt, wo aber eine implizite Konvertierung möglich ist?

Und weiterhin wundert mich die Fehlermeldung: Wieso ist da die Rede von einem Aufruf?
MrSm!th is offline  
Old 11/10/2013, 12:34   #8
 
elite*gold: 0
Join Date: Aug 2012
Posts: 236
Received Thanks: 94
Gute Frage, was möchtest du denn erreichen?

Wenn eine Signatur exakt passt, wird sie genommen, selbst wenn sie variadische Templates nutzt. Wenn also function<F>(F&&) mit F=testclass& am besten passt, wird das auch genutzt.

Da musst du wohl auf Konzepte warten.

Ich glaube, GCC hat recht und Microsoft mag implizite Konvertierungsoperatoren nicht.

Die Fehlermeldung besagt, dass jener function-Konstruktor gewählt wurde und so getan wurde, als sei das Argument ein Funktionsobjekt. Nur lässt es sich nicht aufrufen, daher der Fehler.
Tasiro is offline  
Thanks
1 User
Old 11/10/2013, 12:49   #9


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,395
Was der Fehler besagt, ist mir schon klar, nur verstehe ich den Grund nicht. Im Konstruktor wird die Funktion doch gar nicht aufgerufen, oder doch?
Den Return Type u.Ä. müsste std::function doch auswerten können, ohne dass ein Aufruf nötig ist. Der Fehler tritt laut MSDN nur auf, wenn tatsächlich ein Aufruf eines inkompatiblen Typs stattfindet (sprich zu viele/wenig Argumente, Datenpointer als Funktionspointer verwenden wollen, etc.).

Irgendwie widersprichst du dir, oder stehe ich gerade auf der Leitung? Wenn eine passende Signatur (auch wenn sie nur aufgrund von Templates passt) immer Vorrang vor Signaturen, die nur mit Konvertierung passen, hat, dann hat doch MSVC mit seinem Verhalten Recht. Wäre mir nur neu, da ich davon ausging, dass normale Funktionen grundsätzlich Vorrang haben und erst nach Ausschöpfen aller Auflösungsschritte auf Template-Funktionen zugegriffen wird, wo dann der Fehler auch Sinn machen würde.
Wie auch immer, dann bleibt mir wohl vorerst nur die explizite Verwendung :/ Ich hatte auf etwas Template-Magic gehofft, um den Fehler zu umgehen.
Mir bleibt natürlich immer noch die Möglichkeit, den operator() zu überladen, aber das wollte ich eigentlich vermeiden, da die Anzahl der Argumente dann beschränkt ist (MSVC hat ja noch keine variadischen Templates).

Erreichen will ich einfach nur, dass testclass überall da genutzt werden kann, wo std::function erwartet wird.
MrSm!th is offline  
Old 11/10/2013, 14:13   #10
 
Raz9r's Avatar
 
elite*gold: 297
Join Date: Dec 2010
Posts: 1,129
Received Thanks: 1,687
Wir betrachten die folgenden vier Fälle:

/*1*/ test = obj; //<- causes error
/*2*/ test = (std::function<void ()>)obj; //<- causes error
/*3*/ test = obj.get(); //<-works
/*4*/ test = obj.operator func(); //<- works


Fall 1
Der aufgerufene Operator ist template<class F> function& operator=(F&& f) und nimmt alles an, dass einen operator() definiert. Das tut dein Objekt nicht.

Fall 2
Sollte funktionieren. Der C-Style Cast sollte zu einem static_cast evaluiert werden, der den von dir definierten impliziten Konvertierungsoperator operator func() aufruft.

Fall 3
Funktioniert, da expliziter Aufruf.

Fall 4
Funktioniert ebenso, da der Aufruf auch hier explizit geschieht. Das zeigt aber auch, wo der Fehler im zweiten Fall liegt: Der Compiler schafft es anscheinend nicht, in der Template-Resolution eine passende implizite Konvertierung zu finden, deren Ergebnistyp einen operator() definiert.

Spätestens mit Konzepten sollte das wirklich erledigt sein. Unter Clang (OS X 10.9, Xcode 5, Apple LLVM 5.0) laufen übrigens alle 4 Fälle, wobei ich mir sicher bin, dass der erste nicht laufen sollte. Es zitiere bitte jemand den Standard und korrigiere mich!
Raz9r is offline  
Thanks
1 User
Old 11/10/2013, 16:20   #11
 
elite*gold: 0
Join Date: Aug 2012
Posts: 236
Received Thanks: 94
Quote:
Originally Posted by MrSm!th View Post
Wie auch immer, dann bleibt mir wohl vorerst nur die explizite Verwendung :/ Ich hatte auf etwas Template-Magic gehofft, um den Fehler zu umgehen.
Mir bleibt natürlich immer noch die Möglichkeit, den operator() zu überladen, aber das wollte ich eigentlich vermeiden, da die Anzahl der Argumente dann beschränkt ist (MSVC hat ja noch keine variadischen Templates).

Erreichen will ich einfach nur, dass testclass überall da genutzt werden kann, wo std::function erwartet wird.
Dein Objekt wird als Funktionsobjekt genutzt werden, du könntest von std::function ableiten (Hexerei, nicht Magie). Oder verwende gleich std::function, was hindert dich daran?
Ab MSVC 1800 (VS2013) gibt es variadische Templates.

Quote:
Originally Posted by Raz9r View Post
/*1*/ test = obj; //<- causes error

Fall 1
Der aufgerufene Operator ist template<class F> function& operator=(F&& f) und nimmt alles an, dass einen operator() definiert. Das tut dein Objekt nicht.
Nicht ganz, es ist func test = obj;
Das entspricht etwa: func test ((func) obj);
MSVC macht daraus: func test (func (obj));
Das ist bei Vernachlässigung des Konvertierungsoperators schon einmal richtig.
Tasiro is offline  
Thanks
2 Users
Old 11/10/2013, 16:37   #12


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,395
Quote:
Originally Posted by Tasiro View Post
Dein Objekt wird als Funktionsobjekt genutzt werden, du könntest von std::function ableiten (Hexerei, nicht Magie). Oder verwende gleich std::function, was hindert dich daran?
ableiten ist nicht wirklich eine Option..wobei doch, vielleicht schon. Das gehe ich mal durch.
Was mich hindert? Es handelt sich dabei um einen Container, der eben nicht nur std::function Objekte enthalten muss, aber es eben kann. Und da macht diese Zuweisung nunmal Probleme.
Quote:
Ab MSVC 1800 (VS2013) gibt es variadische Templates.
Danke für die Info, das war mir nicht bekannt.
MrSm!th is offline  
Old 11/10/2013, 16:53   #13
 
Raz9r's Avatar
 
elite*gold: 297
Join Date: Dec 2010
Posts: 1,129
Received Thanks: 1,687
Warum verwendest du nicht einfach operator() als kleine Umleitung?
Raz9r is offline  
Old 11/10/2013, 17:19   #14
 
elite*gold: 0
Join Date: Aug 2012
Posts: 236
Received Thanks: 94
Hier noch ein zu dem Sachverhalt.

Laut Standard darf der Ausdruck obj() nicht als obj.operator func() () ausgewertet werden, wohl aber als obj.operator void(*)() (), wenn es diesen Operator gäbe.
Tasiro is offline  
Thanks
1 User
Old 11/10/2013, 17:20   #15


 
MrSm!th's Avatar
 
elite*gold: 7110
Join Date: Jun 2009
Posts: 28,904
Received Thanks: 25,395
Werde ich wohl tun, ist ohne variadic templates nur so aufwändig :<

edit:

Dass obj.operator func()() nicht implizit funktionieren kann, war mir schon klar, da der () Operator auch sicherlich höhere Priorität hat als Konvertierungen (war zumindest mein Gedanke dabei).
MrSm!th is offline  
Reply


Similar Threads Similar Threads
Running Function 2 after Function 1 finished
09/15/2013 - AutoIt - 3 Replies
Hey, its me again. Im stuck on a problem since yesterday and as much as i hate to ask for help, i really dont know what else to try. I want Function 2 to run after Function 1 has finished. I tried GuiCtrlSetOnEvent and MsgLoop, but i dont really understand it. I tried to read tutorials but they didnt help at all. The line that are underline is what im talking about. I want gamestart() to run first and when its finished, i want iniviteteam() to run. #AutoIt3Wrapper_UseX64=n...
function
07/23/2012 - Rappelz Private Server - 4 Replies
Hi pepole Trying to make Lua Code But i cant find The Function to Open Store :D anyone can help l
Function Box
09/27/2011 - Combat Arms - 5 Replies
Hey undzwar hab ich eine frage von den DailyJob kriegt man ja auch eine Function box und wollte fragen ob man da nur wsachen für 1 day oder mehrere tage bekommen kann bedanke mcih schonmal für eure antworten :)
[VIP-function] ToxicSYS [VIP-function]
08/14/2010 - WarRock Hacks, Bots, Cheats & Exploits - 1 Replies
heeeey E-pvpers :pimp: this is a new hack by TSYS Status : UNDETECTED Functions (VIDEO) : YouTube - WarRock - Bikini event VIP hack
[HELP] Function
08/02/2010 - EO PServer Hosting - 2 Replies
Where can I find this function "gamecard> = 1" within my



All times are GMT +2. The time now is 11:01.


Powered by vBulletin®
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2024 elitepvpers All Rights Reserved.