2015-12-31 12 views
13

Kommend von einer Python Welt, finde ich die Funktion std::iota sehr begrenzt. Warum ist die Schnittstelle darauf beschränkt, keine UnaryFunction zu nehmen?Std :: Iota ist sehr begrenzt

Zum Beispiel kann ich

>>> x = range(0, 10) 

in

std::vector<int> x(10); 
std::iota(std::begin(x), std::end(x), 0); 

konvertieren Aber wie würde man tun:

>>> x = range(0,20,2) 

oder sogar

>>> x = range(10,0,-1) 

Ich weiß, dass es trivial ist, eine solche Funktion zu schreiben oder Boost zu verwenden, aber ich dachte mir, dass C++ - Komitee diesen Entwurf sorgfältig ausgewählt haben muss. So fehlt mir eindeutig etwas aus C++ 11.

+1

Sie 'std verwenden können :: verwandeln 'wenn Sie eine andere Operation über einen Vektor ausführen möchten. –

+2

Siehe http://stackoverflow.com/q/1977339/2301450 – vaultah

+3

Werfen Sie einen Blick auf std :: generate, aber die Quintessenz ist, dass es in C++ noch keine wirklich elegante Standardbibliothekslösung gibt. – MikeMB

Antwort

11

Aber wie würde man tun:

x = range(0,20,2) 

Alternativ zu std::generate() (siehe andere Antwort), können Sie Ihre eigene einstellige Funktion zu std::iota() bieten, sie müssen nur operator++() genannt werden :

#include <iostream> 
#include <functional> 
#include <numeric> 
#include <vector> 

template<class T> 
struct IotaWrapper 
{ 
    typedef T type; 
    typedef std::function<type(const type&)> IncrFunction; 

    type value; 
    IncrFunction incrFunction; 

    IotaWrapper() = delete; 
    IotaWrapper(const type& n, const IncrFunction& incrFunction) : value(n), incrFunction(incrFunction) {}; 

    operator type() { return value; } 
    IotaWrapper& operator++() { value = incrFunction(value); return *this; } 
}; 

int main() 
{ 
    IotaWrapper<int> n(0, [](const int& n){ return n+2; }); 
    std::vector<int> v(10); 
    std::iota(v.begin(), v.end(), n); 

    for (auto i : v) 
     std::cout << i << ' '; 
    std::cout << std::endl; 
} 

Ausgabe: 0 2 4 6 8 10 12 14 16 18

Demo


Hier eine Vorstellung davon, wie man Range() implementieren könnte:

struct Range 
{ 
    template<class Value, class Incr> 
    std::vector<Value> operator()(const Value& first, const Value& last, const Incr& increment) 
    { 
     IotaWrapper<Value> iota(first, [=](const int& n){ return n+increment; }); 
     std::vector<Value> result((last - first)/increment); 
     std::iota(result.begin(), result.end(), iota); 
     return result; 
    } 
}; 

Demo

20

wie wäre es mit std::generate?

int n = -2; 
std::generate(x.begin(), x.end(), [&n]{ return n+=2; }); 
int n = 10; 
std::generate(x.begin(), x.end(), [&n]{ return n--;}) 
+0

Allerdings kann dies das Problem in der Frage beheben, ich denke, Autor fragte über 'std :: iota' Überladung zu etwas wie' std :: iota (Std :: Begin (X), Std :: End (X), 0 , 2) 'wo' 2 'ein Schritt der Iteration ist - warum C++ 11 kein ähnliches hat. Also diese Frage ist meiner Meinung nach eher C++ Standard Commitee. –