2015-02-06 15 views
5

Jestem stosunkowo nowy w C++ i jest to mój pierwszy post bardzo, więc być delikatny ;-)Przechodząc do dynamicznego funktor STL

rozumiem jak przekazać wskaźników funkcji lub obiektów funkcyjnych, jak wiele funkcji STL wymagają. Nie jest dla mnie jasne, jak używać tego w połączeniu z dziedziczeniem.

W szczególności chciałbym wywołać funkcję stl z kilkoma funktorami dziedziczącymi od funktora bazowego. Nie znalazłem żadnych istotnych uwag lub najlepszych praktyk na ten temat. Oto uproszczony fragment kodu:

struct generator{ 
    virtual int operator()() = 0; 
    virtual ~generator(){}; 
}; 

struct A : public generator{ 
    int operator()(); 
}; 

struct B : public generator{ 
    int operator()(); 
}; 

int main() 
{ 
    auto v = std::vector<std::array<int, 500>>(2); 
    std::array<std::shared_ptr<generator>, 2> functors = {{std::make_shared<A>(), 
                 std::make_shared<B>()}}; 
    for (size_t i = 0; i < functors.size(); ++i) 
    std::generate(std::begin(v[i]), std::end(v[i]), 
        *(functors[i])); 
    return 0; 
} 

Kompilacja daje:

clang++ -std=c++11 -g -Wall -Wextra test_stackoverflow.cpp 
test_stackoverflow.cpp:25:5: error: no matching function for call to 'generate' 
    std::generate(std::begin(v[i]), std::end(v[i]),*(functors[i])); 
    ^~~~~~~~~~~~~ 
/usr/lib/gcc/i686-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_algo.h:5003:5: note: candidate template ignored: substitution 
     failure [with _ForwardIterator = int *, _Generator = generator]: parameter type 'generator' is an abstract class 
    generate(_ForwardIterator __first, _ForwardIterator __last, 

Tak rodzaj * (funktory [i]) jest generator. Który nie pozwoli na dynamiczny dostęp do operatorów :: ::() i B :: operator(). Rozumiem, jak (rdzenia) rozwiązać to. na przykład

std::generate(std::begin(v[i]), std::end(v[i], 
       [&]{ return functors[i]->operator()(); }; 

To wydaje się raczej zaciemnione i szukam jaśniejszego sposobu na osiągnięcie moich celów.

Jak zwykle mija się takie dynamiczne funktory. Lub jeśli jest to niezadowolone, jaka jest najlepsza alternatywa?

Każda pomoc lub sugestie są mile widziane.

Odpowiedz

1

Problem, jak być może już wiesz, polega na tym, że std::generate pobiera generator przez wartość. Aby przekazać obiekt polimorficzny, musisz przejść przez odniesienie.

I jest rozwiązanie dla tego rodzaju problemu w C++ 11 (oprócz opcji lambda, która jest jeszcze bardziej elegancka niż to, co mieliśmy przed C++ 11, wierzę). Rozwiązaniem jest std::ref. Zwraca opakowanie referencyjne, które można przekazać według wartości.

ten powinien pracować dla Ciebie:

std::generate(std::begin(v[i]), std::end(v[i]), 
       std::ref(*(functors[i]))); 

powód, dla którego można przekazać obwolut referencyjne jako funktora, jest to, że wdrożenie operator()

+0

Również 'std :: zakresie funkcji –

+0

potwierdzone, może przekazuj 'std :: ref' do algorytmów. Nie wiedział tego. http://coliru.stacked-crooked.com/a/db815184c44240ad –

+0

Będę szczery. Nigdy nie słyszałem o std :: ref. Więc dziękuję za to. Czy uważasz, że lambda ma być preferowana, a jeśli tak, dlaczego? – APevar