2017-04-25 5 views
1

Also, ich habe ein Verfahren und seine Überlastung für eine Klasse, wie folgt geschrieben:Compiler nicht Typen abzuleiten bei der Verwendung von std :: function

bool my_for_each(someIterator begin, someIterator end, bool (*_lambda)(someIterator)); 

void my_for_each(someIterator begin, someIterator end, void (*_lambda)(someIterator)); 

Wie Sie sehen können, der einzige Unterschied ist die Unterschrift eine übergebene Funktion, dh ihr Rückgabetyp. Obwohl der Code funktioniert oben völlig in Ordnung, wenn ich es nennen:

my_for_each(iteratorBegin, iteratorEnd, [](someIterator) {; }); // calls void version 

my_for_each(iteratorBegin, iteratorEnd, [](someIterator)->bool {return false; }); // calls bool version 

..., wenn ich die my_for_each Funktion schreiben, wie folgt:

bool my_for_each(someIterator begin, someIterator end, std::function<bool(someIterator)> _lambda); 

void my_for_each(someIterator begin, someIterator end, std::function<void(someIterator)> _lambda); 

Der Code nicht kompilieren, wenn ich die Funktion aufrufen auf die gleiche Weise (C2668 mehrdeutiger Aufruf der überladenen Funktion). Obwohl, wenn ich die Funktion manuell gewirkt habe:

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<void(someIterator)>>([](someIterator) {; })); //calls void version 

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<bool(someIterator)>>([](someIterator) -> bool { return false; })); //calls bool version 

Der Code funktioniert einwandfrei. Also frage ich mich nur:

  1. Warum ist normale Funktion Zeiger Typ Abzug "stärker" als die Standard-Vorlage eins?
  2. Gibt es eine Art Workaround, um die allgemeinere Version zu verwenden, während der Parameter nicht manuell übergeben wird?

Der Compiler ist VS2015.

Dank und einen schönen Tag!

+0

@ FrançoisAndrieux fixiert, nur ein Übertragungsfehler – Alfaix

+0

Was ist die Bedeutung der Rückgabewerte für die 'my_for_each' Funktionen? –

+0

Es scheinen zwei Iteratoren zu sein, die einen Bereich bilden, und eine Funktion, die einen Iterator akzeptiert und etwas tut. Ich bin mir nicht sicher, was mit all den Bool's in der zweiten Version gemacht wird (vermutlich entweder an und oder). –

Antwort

3

std::function und Lambdas haben unterschiedliche Typen, was bedeutet, dass das zweite Beispiel eine implizite Konvertierung vom Lambda-Typ zu std::function erfordert.

Das Problem ist, dass das Lambda, die bool zurückgibt, kann implizit sowohl std::function<bool(T)> und std::function<void(T)> umgewandelt werden, so dass beide Überlastungen sind gleichermaßen gültige Wahl für Ihren Anruf, was zu einer Mehrdeutigkeit Fehlern. Wenn Sie sie manuell auf die richtige std::function umwandeln, wird die Mehrdeutigkeit explizit aufgelöst.

Edit: Umgehung

Sie dieses Problem, indem sie einen Zusatz Templat Überlastung, die jede Art von abrufbaren Typ akzeptiert lösen kann, folgert den Rückgabetyp für die abrufbaren Art und Preforms die Besetzung automatisch. Ich habe someIterator zu einem Vorlagenargument für die Allgemeinheit geändert. Da Sie keine Implementierungsdetails für Ihre my_for_each Funktionen zur Verfügung gestellt haben, habe ich diese Implementierungen weggelassen. Da es scheint, dass Sie nur void und bool Rückgabetypen unterstützen möchten, habe ich eine static_assert hinzugefügt, um einen klaren Compiler-Fehler zu generieren, falls nicht unterstützte Rückgabetypen bereitgestellt werden.

#include <functional> 
#include <type_traits> 

// Implement for std::function<bool(iter)> 
template<class I> 
bool my_for_each(I begin, I end, std::function<bool(I)> lambda); 

// Implement for std::function<void(iter)> 
template<class I> 
void my_for_each(I begin, I end, std::function<void(I)> lambda); 

// Dispatch to the right overload 
template<class T, class I> 
auto my_for_each(I begin, I end, T&& lambda) 
{ 
    using return_type = decltype(lambda(begin)); // Obtain the return type of lambda 
    static_assert(std::is_same<return_type, bool>::value || std::is_same<return_type, void>::value, 
     "my_for_each only accepts function objects that return void or bool"); 
    using function_type = std::function<return_type(I)>; // The type to cast lambda to 
    return my_for_each(begin, end, function_type(std::forward<T>(lambda))); // Preform the cast 
} 
+1

Ein Update würde diese Antwort verbessern. – Yakk

+0

Also, wenn ich meine eigenen Callable-Objekte verwenden möchte, muss ich sie jedes Mal static_cast, ist das korrekt? – Alfaix

+0

@Alfaix Ich habe die Antwort mit einem Fix bearbeitet, um zu vermeiden, dass jedes Mal manuell gecastet werden muss. –

2

Der Grund ist die Tatsache, dass nicht erfassende Lambdas nur in Funktionszeiger umgewandelt werden können, der Argumente der verwendeten Typen akzeptiert.

Auf der anderen Seite hat std::function einen Vorlagen-Konstruktor, der alles akzeptiert. So könnten sowohl std::function<bool...> als auch std::function<void ...> aus Ihrem Lambda für die Überladungsauflösung von my_for_each erstellt werden. (Beachten Sie, dass diese Objekte jedoch nicht erstellt werden können).

Verwandte Themen