2015-12-31 13 views
13

Pochodzę ze świata Python, uważam, że funkcja std::iota jest bardzo ograniczona. Dlaczego interfejs jest ograniczony, aby nie pobierać żadnego UnaryFunction?std :: iota jest bardzo ograniczony

Na przykład można przekonwertować

>>> x = range(0, 10) 

do

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

Ale jak można by zrobić:

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

lub nawet

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

Wiem, że to jest trywialne, aby napisać jedną taką funkcję lub użyć funkcji Boost, ale doszedłem do wniosku, że komitet C++ musiał ostrożnie wybrać ten projekt. Tak więc wyraźnie brakuje mi czegoś z C++ 11.

+1

można użyć std :: ' przekształcać 'jeśli chcesz wykonać inną operację nad wektorem. –

+2

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

+3

Spójrz na std :: generate, ale najważniejsze jest to, że nie ma jeszcze eleganckiego standardowego rozwiązania biblioteki w C++. – MikeMB

Odpowiedz

11

Ale jak można by zrobić:

x = range(0,20,2) 

Alternatywnie do std::generate() (zobacz inne odpowiedź), można podać własną funkcję jednoargumentowy do std::iota(), to po prostu trzeba nazwać operator++() :

#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; 
} 

Wyjście: 0 2 4 6 8 10 12 14 16 18

Demo


Oto pomysł, jak można wdrożyć Range():

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

co powiecie na: 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

Jednak może to rozwiązać problem w pytaniu, myślę, że autor pytał o przeciążenie 'std :: iota' do czegoś takiego jak' std :: iota (std :: begin (x), std :: end (x), 0 , 2) 'gdzie' 2' jest krokiem iteracji - dlaczego C++ 11 nie ma takiego jak on. Tak więc to pytanie w mojej opinii bardziej dotyczy C++ standardowego commitee. –

Powiązane problemy