2016-03-29 9 views
1

Ich möchte eine Lambda/Funktion fragen, wie viele Parameter es verwendet. Klein (Pseudo-) Beispielcode:Anzahl der Argumente von einem Lambda/Funktion abfragen

template <class InputIterator, class Predicate> 
bool visitAll(InputIterator f, InputIterator l, Predicate p, UserData* d=nullptr) 
{ 
    for(; f != l; ++f) 
    { 
     if(number_of_arguments(p) == 1) 
     { 
      if(!p(*f)) 
       return false; 
     } 
     else 
     { 
      if(!p(*f, *d)) 
       return false; 
     } 
    } 
} 

Beachten Sie, dass die Funktion, die ich für number_of_arguments(...) ist bin zu fragen. Ich habe in der Closure und Std :: Funktion Referenz gesucht, aber keine Ahnung von einer Lösung gefunden.

Danke für Ihre Hilfe!

+1

Es ist nicht möglich, und wenn Sie genau hinsehen, um die Standard-Library-Funktionen ein Prädikat nehmen (zum Beispiel [die Standardbibliothek Algorithmus Funktionen] (http://en.cppreference.com/w/cpp/algorithm)) erhalten Sie Sehen Sie, dass keiner von ihnen diese Art von Funktionalität hat, stattdessen haben sie unterschiedliche Überladungen, wenn sie unterschiedliche Prädikate benötigen. –

Antwort

1

Offensichtlich macht der Code, wie Sie gepostet, nicht viel Sinn, als sowieso p(*f) oder p(*f, *d) würde nicht kompilieren. Daher müssen Sie diese in zwei Vorlagen spalten, und dann können Sie die Anzahl der Argumente von Predicate testen einen ziemlich einfachen SFINAE Ansatz:

template <class InputIterator, class Predicate> 
bool visitAll(InputIterator f, InputIterator l, Predicate p, UserData* d=nullptr, 
    decltype(declval<Predicate>()(*declval<InputIterator>()),1) unused = 1) 
{ 
    cout << "1" << std::endl; 
    for(; f != l; ++f) 
    { 
     if(!p(*f)) 
      return false; 
    } 
    return true; 
} 

template <class InputIterator, class Predicate> 
bool visitAll(InputIterator f, InputIterator l, Predicate p, UserData* d=nullptr, 
    decltype(declval<Predicate>()(*declval<InputIterator>(), declval<UserData>()),1) unused = 1) 
{ 
    cout << "2" << std::endl; 
    for(; f != l; ++f) 
    { 
     if(!p(*f, *d)) 
      return false; 
    } 
    return true; 
} 

Verbrauch:

std::vector<int> a{1,2}; 
const auto t = [](int x){ return 1;}; 
const auto t2 = [](int x, UserData y){ return 1;}; 

UserData d; 
visitAll(a.begin(), a.end(), t); 
visitAll(a.begin(), a.end(), t2, &d); 

Natürlich können Sie verwenden std::bind zu vermeiden, Code-Duplizierung durch den Aufruf der ersten Version von der zweiten.


Ein weiterer Ansatz ist Code zu verwenden, ähnlich wie bei std::bind überprüft, dass es bekam benötigte Anzahl von Argumenten:

template<typename _Func> 
struct noa_helper { 
}; 

template<typename _Ret, typename... _Args> 
struct noa_helper<_Ret (*)(_Args...)> { 
    static int noa() { return sizeof...(_Args); } 
}; 

template<class F> 
int number_of_arguments(F f) { 
    return noa_helper<typename std::decay<F>::type>::noa(); 
} 

void foo(); 
int bar(int x, int y); 
... 
std::cout << number_of_arguments(foo) << std::endl; // prints 0 
std::cout << number_of_arguments(bar) << std::endl; // prints 2 

Diese nur für echte Funktionen arbeitet, nicht lambdas, noch std::function, obwohl einige wahrscheinlicher Vorlagenmagie kann es für die letzten beiden Kategorien arbeiten lassen.

+0

Der Pseudocode sollte natürlich nur die Absicht visualisieren. Danke für die gute Antwort! Obwohl der Code in einem segfault ausgeführt wird, war nur eine kleine Änderung erforderlich, um es auszuführen: UserData d; Besuch (a.begin(), a.end(), t2, &d); Andernfalls wäre die nullptr dereferenced worden. – nesono

Verwandte Themen