Proble z if_then_else_return z boost::lambda

0

Witam, mam mały problem z wyrażeniem if_then_else_return z boost::lambda. Poniższy przykład pochodzi z książki "Beyond C++ STL", niestety u mnie (VS2008, boost v1.43.0) nie działa zgodnie z założeniami (kompiluje się, ale do i nie jest przypisywana wartość wyrażenia". Jeśli ktoś wie, czemu i po wykonaniu nie ma wartości 10 proszony jest o podzielenie się wiedzą. Uwagi typu u mnie działa też będą pomocne :)

#include <iostream>
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/if.hpp"

int main() {
	using namespace boost::lambda;
	int i=0;
	int value=12;
	var(i)=(if_then_else_return(_1>=10, constant(10), _1))(value);
	std::cout<<i;
}
 
0

nie kompiluje się na:
VS2008, boost 1.46.1 (chyba najnowszy)
wynik:

1>------ Build started: Project: 179973-boostlambda, Configuration: Debug Win32 ------
1>Compiling...
1>x.cpp
1>c:\workplace\libs\boost\boost_1_46_1\boost\lambda\if.hpp(315) : error C2664: 'boost::lambda::detail::return_type_deduction_failure<<unnamed-symbol>>::return_type_deduction_failure(const boost::lambda::detail::return_type_deduction_failure<<unnamed-symbol>> &)' : cannot convert parameter 1 from 'int' to 'const boost::lambda::detail::return_type_deduction_failure<<unnamed-symbol>> &'
1> with
1> [
1> <unnamed-symbol>=boost::lambda::detail::return_type_2_ifthenelsereturn<1,true,true,false,int,int &>
1> ]
1> Reason: cannot convert from 'int' to 'const boost::lambda::detail::return_type_deduction_failure<<unnamed-symbol>>'
1> with
1> [
1> <unnamed-symbol>=boost::lambda::detail::return_type_2_ifthenelsereturn<1,true,true,false,int,int &>
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
1> c:\workplace\libs\boost\boost_1_46_1\boost\lambda\detail\lambda_functors.hpp(194) : see reference to function template instantiation 'RET boost::lambda::lambda_functor_base<Act,Args>::call<const boost::lambda::detail::return_type_deduction_failure<<unnamed-symbol>>,A,const boost::tuples::null_type,const boost::tuples::null_type,const boost::tuples::null_type>(A &,B &,C &,Env &) const' being compiled
1> with
1> [
1> RET=const boost::lambda::detail::return_type_deduction_failure<boost::lambda::detail::return_type_2_ifthenelsereturn<1,true,true,false,int,int &>>,
1> Act=boost::lambda::other_actionboost::lambda::ifthenelsereturn_action,
1> Args=boost::tuples::tuple<boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<boost::lambda::relational_actionboost::lambda::greaterorequal_action,
boost::tuples::tuple<boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,const int,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>>,boost::lambda::lambda_functor<
boost::lambda::identity<const int="int">>,boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,boost::tuples::null_type,boost::tuples::null_type,
boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>,
1> <unnamed-symbol>=boost::lambda::detail::return_type_2_ifthenelsereturn<1,true,true,false,int,int &>,
1> A=int,
1> B=const boost::tuples::null_type,
1> C=const boost::tuples::null_type,
1> Env=const boost::tuples::null_type
1> ]
1> c:\workplace\4p\179973-boostlambda\x.cpp(11) : see reference to function template instantiation 'const boost::lambda::detail::return_type_deduction_failure<<unnamed-symbol>> boost::lambda::lambda_functor<T>::operator ()<int>(A &) const' being compiled
1> with
1> [
1> <unnamed-symbol>=boost::lambda::detail::return_type_2_ifthenelsereturn<1,true,true,false,int,int &>,
1> T=boost::lambda::lambda_functor_base<boost::lambda::other_actionboost::lambda::ifthenelsereturn_action,boost::tuples::tuple<boost::lambda::lambda_functor
<boost::lambda::lambda_functor_base<boost::lambda::relational_actionboost::lambda::greaterorequal_action,boost::tuples::tuple<boost::lambda::lambda_functor
<boost::lambda::placeholder<1>>,const int,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>>,boost::lambda::lambda_functor<boost::lambda::identity<const int="int">>,
boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>,
1> A=int
1> ]
1>Build log was saved at "file://c:\workplace\4p\179973-boostlambda\Debug\BuildLog.htm"
1>179973-boostlambda - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

zerknij na http://www.boost.org/doc/libs/1_46_1/doc/html/lambda/le_in_details.html sekcja Lambda expressions for control structures
if_then_else i if_then_else_return sa dwoma roznymi rzeczami i kieruja sie podobnymi zasadami jak ich oryginalne konstrukcje.

if_then_else_return jest odpowiednikiem test?valtrue:valfalse, i tym samym wymaga aby lewe i prawe wyrazenie wokół : produkowaly takie same typy zwracane.

a czym jest _1 ?
_1 to placeholder, a konkretniej mowiac konkretne, globalne wystapienie pewnego funktora, zwracajacego swoj pierwszy argument.
jesli wiec teraz napisales:

var(i)=(if_then_else_return(_1>=10, constant(10), _1))(value);

to hen-tam-w-głębi ów ?: ma do "zrzutowania" na wspolny typ zwracany z lewej strony "int", a z prawej strony "funktor-nieokreslony". nieokreslony, gdyz dopiero duuzo pozniej wynik if-then-else-return'a jest odpalany operatorem () z wlasciwa wartoscia parametru.

teoretycznie, jezeli silnik kompilatora bylby bardzo rozwiniety, to analiza drzewa wyrazen w dol i w gore moze i moglby sie domyslic, ze ow funktor w głębi powinien byc typu <int>, ale .... nie moze, albo nie daje rady.

najprostsze rozwiazanie, jakie znalazlem, to zmuszenie kompilatora, aby zamiast placeholdera-nie-do-konca-znanego, wygenerowal na miejscu drugiego czlonu if-then-else-return cos znanego, cos co bedize mialo scisle okreslony i zgodny typ zwrotki, na przyklad trywialne..:

var(i)=(if_then_else_return(_1>=10, constant(10), _1+0 ))(value);

i to naprawde dziala, na moim w/w vs2008 + boost1.46.1 kompiluje sie i zwraca dla 12 -> 10.

jestem jednak prawie pewien, ze "wczesniej" podobne wyrazenia sie kompilowaly bez problemu, i kompilator dawal rade przesledzic ze _1 odpowiada typowi 'value'. jednak, uzywajac vs2008, musisz przywyknac ze nie wszytko jest w 100% idealnie rozpatrywane. szczesliwie, na 1.46.1 dostaje sie blad kompilacji, ale sam juz zauwazyles ze nie zawsze tak jest. template'y i typeinference w C++ to naprawde wredne bestie do analizy, a vs do pelni standardu c++ jeszcze nie dociagnal! (z tego co pamietam:) )

nie ręczę, że w/w wytlumaczenie problemu jest faktycznie poprawne, ale tak mi sie w tej chwili wydaje.
trzeba jednak wziac poprawke, ze boost::lambda uzywalem dosc szeroko za czasow/w okolicach wersji 1.36 i 1.42, wiec moglo sie troche pozmieniac, a i .... bylo to kawalek ładny czasu temu, i chocby z tego powodu teraz niektore szczegoly moglem lekko przekrecic

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