2016-12-10 1 views
3

Dies ist eine allgemeine, skelettierte Version eines Vorlagenproblems, das ich in C++ habe. Ich kann nicht ganz herausfinden, wie man die bar Funktionsschablone als plausiblen Kandidaten erkennt, wenn sie von foo aufgerufen wird.C++ Kandidat Vorlage Ignorierter Fehler beim Übergeben von Lambda als Argument für std :: function

#include <iostream> 
#include <cstdlib> 
#include <unordered_map> 

template<class T> 
std::unordered_map<std::string, T> getStr2TMap() { 
    return {}; // suppose logic here is a bit more involved 
} 

template<class T> 
std::unordered_map<int, T> getInt2TMap() { 
    return {}; // suppose logic here is a bit more involved 
} 

template<class U, class T> 
void bar(
    const std::function<void (std::unordered_map<U, T>&&)>& baz 
) { 
    if (rand() % 2 > 0) { 
    baz(getInt2TMap<T>()); 
    } else { 
    baz(getStr2TMap<T>()); 
    } 
} 

template<class T> 
void foo(
    const std::unordered_map<std::string, T>& map1 
) { 
    bar([&map1](auto&& map2) { 
    // do some things with map1 and map2 
    }); 
} 

int main() { 
    std::unordered_map<std::string, int> myMap; 
    foo<int>(myMap); 
} 

EDIT

stark vereinfachte Version des Codes, gleiche Fehler. Ich suche jedoch nach Lösungen für die obige Version, nicht diese.

#include <iostream> 
#include <functional> 
#include <unordered_map> 

template<class T> 
void foo(
    const std::function<void (std::unordered_map<int, T>&&)>& bar 
) { 
    std::unordered_map<int, T> myMap; 
    bar(myMap); 
} 

int main() { 
    foo([](auto&& m) { 
    }); 
} 
+0

Es sieht aus wie ein Teil des Problems ist hier, dass ich explizit eine Art arg zu übergeben, wenn ich 'foo' nennen? Gibt es eine Möglichkeit, es abzuleiten? – Kvass

Antwort

3

Der gezeigte Code versucht T und U für die folgende Art Versuch, die Template-Funktion übergeben wird, für den Lambda-Parameter

std::function<void (std::unordered_map<U, T>&&)> 

Der Abzug ableiten:

[&map1](auto&& map2) {} 

Das Problem ist, dass ein Lambda kein std::function irgendeiner Art ist. Es ist ein:

... temporäres Objekt einzigartigen unbenannte nicht gewerkschaftlich nicht-Aggregat Klasse Typs, der als "Verschluss" Typ bekannt, ...

(Cite)

Anders gesagt, ist ein Lambda-Objekt eine Instanz einer Klasse mit einer operator(), die den Lambda-Code ausführt (und erfasste Objekte werden in Member der unbenannten Klasse transformiert). Da es sich also nicht um eine std::function handelt, ist es nicht möglich, std::function Typen daraus abzuleiten.

Da es ein aufrufbar Typ ist, kann es zu einem std::function, obwohl umgewandelt werden:

bar(static_cast<std::function<void(std::unordered_map<std::string, T> &&)>> 
     ([&map1](auto&& map2) { 
      // do some things with map1 and map2 
     })); 
} 

Das wird die bar() Template-Funktion erkannt erhalten.

Aber es gibt noch ein zweites Problem mit dem gezeigten Code:

if (rand() % 2 > 0) { 
    baz(getInt2TMap<T>()); 
    } else { 
    baz(getStr2TMap<T>()); 
    } 

auf der Rolle des Würfels Je wird der Code versucht, entweder eine ungeordnete Karte von Strings zu übergeben, oder eine ungeordnete Karte von ints baz().

Das ... geht nicht zur Arbeit. In diesem Stadium des Spiels ist baz ein std::function irgendeiner Art. Es ist keine Vorlage. Als solches kann es nur einen Parameter eines Typs annehmen.

Falls Sie static_cast hinzufügen und machen bar() ein:

baz(getStr2TMap<T>()); 

die Tatsache passen, dass der Anrufer eine ungeordnete Karte von Strings ist vorbei, sollte der resultierende Code kompilieren.

Was passiert in Ihrem bar() ist ein separates Problem.Mit der static_cast beantwortet die Frage, wie Sie die Kandidatenvorlage bar erkannt bekommen.

+0

das 'rand()' Ding war mein Versuch, mehr involvierte Logik anzunähern, wo ich nicht wirklich weiß, was der Schlüsseltyp ist. In Wirklichkeit wird es nicht mit zwei verschiedenen Schlüsseltypen zu tun haben, nur einem unbekannten. Ich glaube, ich habe es hier vereinfacht. – Kvass

1

Sam macht eine gute Beobachtung darüber, wie U in bar inkonsistent ist. Aber in Ihrem einfachen Beispiel, warum all der Mühe const std::function<void (std::unordered_map<int, T>&&)>& durchlaufen, wenn Sie schreiben können:

#include <iostream> 
#include <functional> 
#include <unordered_map> 

template<class T, class Func> 
void foo(
    Func bar 
) { 
    std::unordered_map<int, T> myMap; 
    bar(myMap); 
} 

int main() { 
    // needs the hint for T, since it isn't used anywhere 
    foo<int>([](auto&& m) { 
    }); 
} 
Verwandte Themen