2012-06-21 5 views
6

Ist es möglich, ein Template-Argument aus einer umgebenden Template-Funktion innerhalb einer lokalen anonymen Funktion zu verwenden? Ich bin mir ziemlich sicher, dass ich nicht eine Vorlage Lambda erklären kann ...Wie Template-Argument in Lambda verwenden?

Zum Beispiel, wie würde ich mich über so etwas wie dies zu tun:

template <typename T> 
void TrimString(std::basic_string<T>& str, const std::locale& loc = std::locale()) 
{ 
    // std::isspace as lambda unary predicate? 
    auto fn = [&loc](T c){ return std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); }; 
    // trim right 
    str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(fn)).base(), str.end()); 
    // trim left 
    str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(fn))); 
} 

Derzeit wird diese erzeugt die folgende Fehlermeldung:

error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>' 

Das ist sinnvoll, da das Lambda keine Ahnung über das Argument T von der umgebenden Template-Funktion hat.

Ich benutze VS2010 und gcc 4.7, aber ich möchte nicht boost verwenden.

Irgendwelche Ideen?

Bearbeiten: Es scheint, ich lag falsch in meiner Annahme, dass das Problem das Template-Argument selbst war. Vielmehr wird die Verwendung von std::not1 mit der Lambda-Funktion kompiliert. Hier ist die ausführlichere Fehlerausgabe:

error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>' 
: see declaration of '`anonymous-namespace'::<lambda0>' 
: see reference to class template instantiation 'std::unary_negate<_Fn1>' being compiled 
      with 
      [ 
       _Fn1=`anonymous-namespace'::<lambda0> 
      ] 
: see reference to function template instantiation 'void TrimString<char>(std::basic_string<_Elem,_Traits,_Ax> &,const std::locale &)' being compiled 
      with 
      [ 
       _Elem=char, 
       _Traits=std::char_traits<char>, 
       _Ax=std::allocator<char> 
      ] 

Müssen Sie explizit den Typ für das Argument erklären, wenn es eine Funktion Typ ist? Ich bin mir nicht sicher, was ich falsch mache noch ...

Antworten:

Option 1: Wenn ich nicht std::not1 verwenden Sie stattdessen den zurückgegebenen Wert in der Lambda-negieren ich das gleiche bekommen Verhalten ohne Problem.

auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); }; 

Option 2: Da das Lambda nicht mehr gleichwertig ist, wie std::isspace als einstelliges Prädikat verhalten würde eine Funktion Objektkonstruktor Besetzung auch den Trick funktioniert.

str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::function<bool(T)>(fn))).base(), str.end()); 
+0

BTW scheint die Fehlermeldung anzuzeigen, dass das Problem woanders liegt, speziell mit dem Lambda deklariert * Namespace * Bereich. – Nawaz

+1

Casting 'fn' wie folgt' std :: not1 (std :: function (fn)) 'funktioniert auch. –

Antwort

6

Sie können T als Parametertyp eines Lambda-Ausdrucks verwenden.Das folgende Programm kompiliert Geldbußen GCC 4.5.1:

include <iostream> 

template<typename T> 
void f(T arg) 
{ 
    auto print = [](T a) { std::cout << a << std::endl; }; 
    print(arg); 
} 

int main() { 
     f(8899); 
     f("Nawaz"); 
     return 0; 
} 

überzeugen Sie sich selbst: http://ideone.com/l32Z6

BTW, scheint die Fehlermeldung, um anzuzeigen, dass das Problem woanders liegt, und zwar mit einem Lambda bei Namespace deklarierte -umfang:

error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>'


nach dem EDIT, alles, was ich sagen kann, ist, dass Sie nicht Verwenden Sie dann std::not1. Tatsächlich brauchst du es nicht einmal. Sie könnten return !whatever-expression im Lambda selbst verwenden.

+0

Hmm ... also ist der OP-Fehler nicht vom Lambda-Argument? – Jason

+0

@Jason: Das scheint es zu sein. – Nawaz

+0

Doh! Ich werde die Frage aktualisieren. – AJG85

2

bearbeiten: Wie @Nawaz weist darauf hin, muss der Fehler Form woanders kommen werden ... was ich beschreiben unten übertrieben ...

decltype verwenden, können Sie etwas tun könnte wie folgt aus:

template <typename T> 
void TrimString(std::basic_string<T>& str, 
       const std::locale& loc = std::locale(), 
       T arg = T()) 
{ 
    auto fn = [&loc](decltype(arg) c){ return std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); }; 

    //...rest of your code 
} 

Dieses (oder missbraucht) die Tatsache nutzt, dass die Expression decltype(arg) auf die Art der arg auswertet , was in diesem Fall der Typ T ist.

+0

Warum 'declltype' verwenden, wenn' T' gut funktioniert? Er muss auch etwas anderes machen. – Nawaz

+0

Ich nahm an, dass sein Fehler von dem kam, was er sagte, das ist die Verwendung von 'T' anstelle eines bekannten Argumenttyps ... offensichtlich zeigt dein Beitrag, dass es kein Problem damit gibt ... – Jason

+0

Wenn ich' capture' arg' und benutze 'declltype' Ich bekomme den gleichen Fehler. Offensichtlich, wenn ich es nicht aufzeichne, beschwert es sich über implict Capture oder keinen Standard-Capture-Modus. Dies könnte in die richtige Richtung gehen, auch wenn es nicht funktioniert ... oder MSVC ist defekt, wenn dies funktionieren sollte. – AJG85

9

Das Problem wird nicht durch Verwendung eines Template-Parameters innerhalb des Lambda verursacht, da der Parameter bereits zum Zeitpunkt der Lambda-Konstruktion in einen Typ aufgelöst wurde. Das Problem ist, dass das von Ihnen definierte Lambda nicht mit std::not1 kombiniert werden kann, was als Argument eine std::unary_function<argument_type,return_type> erfordert.

Der einfachste Weg, um das Problem zu lösen, ist nicht std::not1, zu verwenden und stattdessen die Prädikation direkt im Lambda-Ausdruck negiert:

auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space,c); }; 

Der komplette Code, und arbeitet 4.7.0 mit GCC kompiliert wird dann:

#include <string> 
#include <algorithm> 
#include <locale> 
#include <iostream> 

template <typename T> 
void TrimString(std::basic_string<T>& str, const std::locale& loc = std::locale()) 
{ 
    auto fn = [&loc](T c){ return !std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space,c); }; 

    str.erase(std::find_if(str.rbegin(), str.rend(),fn).base(), str.end()); 
    str.erase(str.begin(), std::find_if(str.begin(), str.end(), fn)); 
} 

int main() { 
    std::basic_string<char> s(" hello "); 
    TrimString(s); 
    std::cout << s << std::endl; 
    return 0; 
} 

Diese Ausgänge

hello 

als expe cted.

+0

Yup, kam gerade zu dieser Schlussfolgerung selbst jetzt, dass ich auf das eigentliche Problem schaute! – AJG85

Verwandte Themen