Boost lambda - problem

0

Niedawno zainteresowałem się boost-em i spośród tego co oferuje za bardzo użyteczne uważam wyrażenia lamba , o których można powiedzieć ,że stanowią poszerzenie możliwości samego języka C++.Bardzo mnie się podoba to co dzięki lamba można osiągnąć- znaczne skrócenie kodu i uczynienie go lepiej czytelnym poprzez definicje obiektów funkcyjnych w miejscu przekazywania ich do funkcji uogólnionych stl-a.We większości przypadków nie mam pojęcia jak to działa a zwłaszcza w jaki sposób
jest określany typ wartości zwracanej po utworzeniu funktora z wyrażeniami arytmetycznymi w środku alechciałbym po prostu móc z tego korzystać.

Teraz przejdę do problemu na jaki natrafiłem podczas testowania możliwości operatorów arytmetycznych wyrażeń lamba. Utworzyłem prostą klasę - complex z 3 składowymi int i zdefiniowanym operatorem +.

#include <iostream>
#include <iterator>
#include <vector> 
#include <string>
#include <algorithm>
#include <iostream>
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/bind.hpp"


class complex
{
int a,b,c;
public:
complex(int a,int b,int c): a(a),b(b),c(c) {}; 
complex() {}
complex& operator=(const complex& arg);                
friend complex operator+(const complex& c1,const complex& c2);
friend std::ostream& operator<<(std::ostream& os,const complex& c);
};

complex& complex::operator=(const complex& arg)
{ 
 if(&arg!=this)
 {
 a=arg.a;
 b=arg.b;
 c=arg.c;
 }
 return *this;
} 


complex operator+(const complex& c1,const complex& c2)
{
  return complex(c1.a+c2.a,c1.b+c2.b,c1.c+c2.c);   
}     

std::ostream& operator<<(std::ostream& os,const complex& c)
{ os<<c.a<<" "<<c.b<<" "<<c.c<<" ";
  return os;
}  



int main() {
  
using namespace boost::lambda;


std::vector<complex> v1;
v1.push_back(complex(1,1,1));
v1.push_back(complex(1,1,1));
v1.push_back(complex(2,2,2));
v1.push_back(complex(3,3,3));

std::vector<complex> v2;
v2.push_back(complex(1,1,1));
v2.push_back(complex(1,2,3));
v2.push_back(complex(2,7,7));
v2.push_back(complex(3,8,9));

std::vector<complex> v3;


std::vector<std::string> s1;
s1.push_back(std::string("s1"));
s1.push_back(std::string("s2"));

std::vector<std::string> s2;
s2.push_back(std::string("s3"));
s2.push_back(std::string("s4"));

std::string s("string");
std::transform(s1.begin(),s1.end(),s2.begin(),s1.begin(),_1+"+"+_2);
std::for_each(s1.begin(),s1.end(),std::cout<<_1<<"\n");


std::transform(v1.begin(),v1.end(),v2.begin(),v1.begin(),_1+_2);


std::cin.get();
return 0;
}

Ze stringami nie ma żadnych problemów. Jest tworzony dwuargumentowy obiekt funkcyjny i wewnątzr niego jest dokonywane działanie string1+"+"+string2 po czym string wynikowy jest umieszczany w pierwszym z 2 przekazanych kontenerów.
Dlaczego to nie działa z obiektami mej klasy (complex) [???] . Zdefiniowałem dla niej operator + i chciałbym osiągnąć to samo co ze stringami czyli 2 complex-y sumujemy i wynikowy obiekt umieszczamy poprzez iterator wyjściowy w tym przypadku w pierwszym z 2 przekazanych kontenerów.
Przy próbie kompilacji dv-c++ sypie błędami min - no match for operator = i wiele innych,które mi nic nie mówią o tym gdzie tkwi problem(jak to zazwyczaj bywa z komunikatami o błędach zwłaszcza gdy ma my do czynienia z szablonami). Gdy usuniecie ostatnie wywołanie transform to program się skompiluje.

0

Drobny dowcip w tym, ze dla string'ow tez nie dziala:)
no, przynajmniej pod msvc2008.

generalnie, chodzi o to, ze kompilator ma problemy z domysleniem sie, jaki jest typ wynikowy Twojego funktora, a wlasciwie funkcji.. jezeli nie polegalbys na automatycznym opakowywaniu poprzez placeholder;y (_1, _2, ..) i napisalbys funktor 'dodaj-complex-complex' to w tymze funktorze umiescilbys informacje 'SIG' ktora by wszystko kompilatorowi podpowiedziala.. a tak musisz uzyc np. boost:

std::transform(v1.begin(),v1.end(),v2.begin(),v1.begin(), boost::ret<complex>(_1 + _2));

co do stringow i msvc2008, dla linii:
std::transform(s1.begin(),s1.end(),s2.begin(),s1.begin(), _1 + "+" + _2 );
zglaszany jest blad konwersji/rzutowania, ktory po przekopaniu sie wskazuje ze visual ma problem z char*/string. modyfikacja explicite mowiaca ze "+" to string:
std::transform(s1.begin(),s1.end(),s2.begin(),s1.begin(), _1 + std::string("+") + _2 );
daje identyczny efekt jak Twoj przy complex: type_deduction_failure/no operator= found
rozwiazanie dalszych problemow poprzez podpowiadanie daje taka linijke:
std::transform(s1.begin(),s1.end(),s2.begin(),s1.begin(), retstd::string( retstd::string(_1 + std::string("+") ) + _2 ));
co juz powoli zaczyna trącić masochizmem i zaczyna sie mijac z celem

PS. szczerze mowiac circa 2 lata temu bylbym w stanie dokladnie powiedziec Tobie, czemy Twoj complex i operator+/= nie sa rozpoznawane przez BL i jak/czywogole mozna w normalniejszy sposob BL'ce podpowiedziec jak z nich skorzystac.. niestety od tamtego czasu praktycznie w ogole go nie uzywalem i na pocieszenie moge tylko dorzucic, ze zamist konstruowac potwory jak ta ostatnia linijka, lepiej machnac na szybko maly funktor:

int main()
{
....
struct cpx_add{ complex operator()(complex const & lhs, complex const & rhs) { return lhs+rhs; } };
std::transform(v1.begin(),v1.end(),v2.begin(),v1.begin(), cpx_add());
...
}
i to dziala bez najmniejszego problemu, zawsze, nie wazne jak skomplikowane sa akcje.. oczywiscie, traci to na pieknie wzgledem _1+_2

1 użytkowników online, w tym zalogowanych: 0, gości: 1