r3519: fun update: add unary & binary composition

URL: https://svn.lrde.epita.fr/svn/oln/trunk ChangeLog: 2009-03-13 Frederic Bour <bour@lrde.epita.fr> fun update: add unary & binary composition. * milena/sandbox/fred/fun/cos.hh, * milena/sandbox/fred/fun/abs.hh: WIP, switching from solve to nsolve. * milena/sandbox/fred/fun/assignability.hh: New. Traits to check function properties using sfinae (should be renamed). * milena/sandbox/fred/fun/binary.hh: New. Binary function * milena/sandbox/fred/fun/compose.hh: New. Compose function. * milena/sandbox/fred/fun/composition.hh: New. Composition result objects definition. * milena/sandbox/fred/fun/cos.cc: New. Test for composition. * milena/sandbox/fred/fun/fun.cc: WIP. * milena/sandbox/fred/fun/meta_function.hh: Added Meta_Function_v2v and Meta_Function_vv2v categories. * milena/sandbox/fred/fun/nsolve.hh, * milena/sandbox/fred/fun/nsolve_binary.hh, * milena/sandbox/fred/fun/nsolve_unary.hh: New. Original trait solver modification now based on typename flag instead of template <class> class * milena/sandbox/fred/fun/thru_morpher.hh: WIP. * milena/sandbox/fred/fun/unary.hh: Update & redesign, especially for composition. --- abs.hh | 1 assignability.hh | 103 ++++++++++++++++++ binary.hh | 137 ++++++++++++++++++++++++ compose.hh | 71 ++++++++++++ composition.hh | 210 ++++++++++++++++++++++++++++++++++++++ cos.cc | 34 ++++++ cos.hh | 12 +- fun.cc | 5 meta_function.hh | 71 ++++++++++++ nsolve.hh | 152 +++++++++++++++++++++++++++ nsolve_binary.hh | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ nsolve_unary.hh | 171 +++++++++++++++++++++++++++++++ thru_morpher.hh | 1 unary.hh | 299 +++++++++++++++++++++++++++++++++++++++++++++++------- 14 files changed, 1526 insertions(+), 43 deletions(-) Index: trunk/milena/sandbox/fred/fun/binary.hh =================================================================== --- trunk/milena/sandbox/fred/fun/binary.hh (revision 0) +++ trunk/milena/sandbox/fred/fun/binary.hh (revision 3519) @@ -0,0 +1,137 @@ +#ifndef BINARY_HH +# define BINARY_HH + +# include <mln/fun/essential.hh> +# include "meta_function.hh" +# include "nsolve.hh" +# include "assignability.hh" + +namespace mln +{ + + namespace fun + { + + namespace spe + { + + // Forward declaration + template <typename Fun, typename T1, typename T2> + struct binary; + + namespace impl + { + + template <typename Fun, typename T1, typename T2> + struct binary_impl : mln::Function_v2v< binary<Fun, T1, T2> > + { + typedef mln_trait_nbinary(Fun, T1, T2) impl; + + typedef typename impl::argument1 argument1; + typedef typename impl::argument2 argument2; + typedef typename impl::result result; + + binary_impl() + : impl_() + { + } + + binary_impl(const impl& f) + : impl_(f) + { + } + + result operator () (const argument1& a, const argument2& b) const + { + return this->impl_.read(a, b); + } + + protected: + impl impl_; + }; + + } // end of namespace mln::fun::spe::impl + + template <typename Fun, typename T1, typename T2> + struct binary + : impl::binary_impl<Fun, T1, T2> + { + typedef impl::binary_impl<Fun, T1, T2> super; + + binary() + : super() + { + } + + binary(const typename super::impl& f) + : super(f) + { + } + + using super::operator(); + }; + + } // end of namespace mln::fun::spe + + template <typename F> + struct binary : mln::Meta_Function_vv2v< binary<F> > + { + + template <typename T1, typename T2> + struct with + { + typedef spe::binary<F, T1, T2> ret; + }; + + template <typename T1, typename T2> + typename with<T1, T2>::ret::result operator()(const T1& a, const T2& b) const + { + typename with<T1, T2>::ret tmp; + return tmp(a, b); + } + + }; + + template <typename F, typename P> + struct binary_param: binary<F> + { + typedef P param; + + binary_param() {}; + binary_param(const param& p) : p_(p) {}; + + void init(const param& p) + { + p_ = p; + } + + param& parameter() + { + return p_; + } + + protected: + param p_; + }; + + template <typename F> + struct binary_param<F, F>: binary<F> + { + typedef F param; + + void init(const param& p) + { + exact(*this) = p; + } + + param& parameter() + { + return exact(*this); + } + }; + + } // end of namespace mln::fun + +} // end of namespace mln + +#endif /* ! BINARY_HH */ Index: trunk/milena/sandbox/fred/fun/cos.hh =================================================================== --- trunk/milena/sandbox/fred/fun/cos.hh (revision 3518) +++ trunk/milena/sandbox/fred/fun/cos.hh (revision 3519) @@ -11,12 +11,15 @@ // COS, bijective namespace fun { - template <typename T> - struct cos : unary<cos, T> {}; + struct cos : unary<cos> {}; } namespace trait { + + namespace next + { + template <typename T> struct set_unary_<mln::fun::cos, mln::value::Floating, T> { @@ -35,12 +38,11 @@ l = math::acos(x); } }; + } - namespace meta - { - typedef unary<mln::fun::cos> cos; } + } #endif /* ! COS_HH */ \ No newline at end of file Index: trunk/milena/sandbox/fred/fun/nsolve_unary.hh =================================================================== --- trunk/milena/sandbox/fred/fun/nsolve_unary.hh (revision 0) +++ trunk/milena/sandbox/fred/fun/nsolve_unary.hh (revision 3519) @@ -0,0 +1,171 @@ +// Copyright (C) 2006, 2008 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. +#ifndef MLN_TRAIT_NSOLVE_UNARY_HH +# define MLN_TRAIT_NSOLVE_UNARY_HH + +/*! + * \file mln/trait/solve_unary.hh + * + * \brief FIXME + * + * + */ + +# include <mln/core/category.hh> +# include <mln/core/routine/exact.hh> +# include <mln/metal/equal.hh> +# include <mln/metal/if.hh> +# include <mln/metal/ret.hh> +# include "nsolve.hh" + + +// FIXME: Just for the record (use it...) + +# ifndef MLN_DEBUG_TRAITS +# endif // ! MLN_DEBUG_TRAITS + + + +namespace mln +{ + + namespace trait + { + + namespace next + { + + namespace internal + { + + + template < typename Name, + typename Category, + typename T > + struct trait_set_unary_; + + template < typename Name, + template <class> class Category, typename _, + typename T > + struct trait_set_unary_< Name, Category<_>, T > + { + typedef typename mln::trait::next::set_unary_<Name, Category, T>::ret ret; + }; + + + // Fwd decls. + template < typename Name, + typename Category, typename T > + struct get_unary_; + + + template < typename user_ret, /* != not_found and != undefined */ + typename Name, + typename Category, typename T > + struct helper_get_unary_ + { + typedef user_ret ret; // The user has defined 'ret' so we return it. + }; + + + template < typename Name, + typename Category, typename T > + struct helper_get_unary_< /* user_ret == */ not_found, + Name, Category, T > + { + typedef not_found ret; // End of search due to a blocker; 'ret' is not found. + }; + + + template < typename Name, + typename Category, typename T > + struct helper_get_unary_< /* user_ret == */ undefined, + Name, Category, T > + { + typedef typename mln::internal::super_category_< Category, T >::ret Super_Category; + typedef typename get_unary_<Name, Super_Category, T>::ret ret; // No user ret definition => Recursion. + }; + + + template < typename Name, + typename Category, typename T > + struct get_unary_ + { + typedef typename trait_set_unary_<Name, Category, T>::ret user_ret; // First get 'user_ret' + typedef helper_get_unary_<user_ret, Name, Category, T> helper; // Set the helper to make a decision. + typedef mlc_ret(helper) ret; // Return. + }; + + + template < typename precise_ret, + typename Name, + typename Category, typename T > + struct helper_choose_unary_wrt_ /* precise_ret != undefined */ + { + typedef precise_ret ret; // -> A precise ret has been defined so it is it. + }; + + template < typename Name, + typename Category, typename T > + struct helper_choose_unary_wrt_< /* precise_ret == */ undefined, + Name, Category, T > + { + typedef typename get_unary_<Name, Category, T>::ret ret; // -> Go up into the category inheritance + // to fetch a ret from 'set_unary_'s. + }; + + template < typename Name, + typename Category, typename T > + struct helper_solve_unary_ + { + typedef typename set_precise_unary_<Name, T>::ret precise_ret; + typedef helper_choose_unary_wrt_< precise_ret, /* undefined or not (?) */ + Name, Category, T> helper; + typedef mlc_ret(helper) ret; + }; + + } // end of namespace mln::trait::next::internal + + + template < typename Name, + typename T_ > + struct solve_unary + { + typedef mln_exact(T_) T; + typedef typename mln::category<T>::ret Category; + typedef internal::helper_solve_unary_< Name, Category, T > meta_code; + typedef typename meta_code::ret ret; + }; + + } // end of namespace mln::trait::next + + } // end of namespace mln::trait + +} // end of namespace mln + + +#endif // ! MLN_TRAIT_NSOLVE_UNARY_HH Index: trunk/milena/sandbox/fred/fun/meta_function.hh =================================================================== --- trunk/milena/sandbox/fred/fun/meta_function.hh (revision 3518) +++ trunk/milena/sandbox/fred/fun/meta_function.hh (revision 3519) @@ -57,6 +57,8 @@ // Fwd decl. template <typename E> struct Meta_Function; + template <typename E> struct Meta_Function_v2v; + template <typename E> struct Meta_Function_vv2v; // Meta_Function category flag type. template <> @@ -81,6 +83,49 @@ Meta_Function(); }; + /*----------------------. + | Unary meta function. | + `----------------------*/ + + template <> + struct Meta_Function_v2v<void> { typedef Meta_Function<void> super; }; + + /// Base class for implementation of function-objects from + /// value to value. + /// + /// The parameter \a E is the exact type. + /// + template <typename E> + struct Meta_Function_v2v : public Meta_Function<E> + { + typedef Meta_Function_v2v<void> category; + + protected: + Meta_Function_v2v(); + Meta_Function_v2v(const Meta_Function_v2v&); + }; + + /*-----------------------. + | Binary meta function. | + `-----------------------*/ + + template <> + struct Meta_Function_vv2v<void> { typedef Meta_Function<void> super; }; + + /// Base class for implementation of function-objects from + /// value to value. + /// + /// The parameter \a E is the exact type. + /// + template <typename E> + struct Meta_Function_vv2v : public Meta_Function<E> + { + typedef Meta_Function_vv2v<void> category; + + protected: + Meta_Function_vv2v(); + Meta_Function_vv2v(const Meta_Function_vv2v&); + }; namespace fun { @@ -109,6 +154,32 @@ // FIXME: Check "with" on E. } + template <typename E> + inline + Meta_Function_v2v<E>::Meta_Function_v2v() + { + } + + template <typename E> + inline + Meta_Function_v2v<E>::Meta_Function_v2v(const Meta_Function_v2v<E>& rhs) + : Meta_Function<E>(rhs) + { + } + + template <typename E> + inline + Meta_Function_vv2v<E>::Meta_Function_vv2v() + { + } + + template <typename E> + inline + Meta_Function_vv2v<E>::Meta_Function_vv2v(const Meta_Function_vv2v<E>& rhs) + : Meta_Function<E>(rhs) + { + } + namespace fun { Index: trunk/milena/sandbox/fred/fun/unary.hh =================================================================== --- trunk/milena/sandbox/fred/fun/unary.hh (revision 3518) +++ trunk/milena/sandbox/fred/fun/unary.hh (revision 3519) @@ -1,18 +1,23 @@ #ifndef UNARY_HH # define UNARY_HH -# include <mln/trait/solve.hh> # include <mln/fun/essential.hh> -# include <mln/fun/internal/resolve.hh> # include "meta_function.hh" +# include "nsolve.hh" +# include "assignability.hh" namespace mln { - // UNARY + namespace fun { + + // Forward declaration, for composition with unary::operator()(Fun) + struct compose; + namespace internal { + template <typename Impl> struct unary_modifier { @@ -22,14 +27,14 @@ typedef unary_modifier lresult; // FIXME: argument or lvalue? ~~~ - unary_modifier(argument& x) - : x_(&x) + unary_modifier(const Impl& impl, argument& x) + : x_(&x), impl_(&impl) { } result to_result() const { - return Impl::read(*x_); + return impl_->read(*x_); }; operator result() const @@ -39,89 +44,307 @@ const result& operator = (const result& r) const { - Impl::write(*x_, r); + impl_->write(*x_, r); return r; } private: argument *x_; + const Impl *impl_; }; - } - template <template <class> class Fun, typename T> - struct unary : mln::Function_v2v< Fun<T> > + } // end of namespace mln::fun::internal + + namespace spe + { + + // Forward declaration + template <typename Fun, typename T> + struct unary; + + namespace impl { - // FIXME: mln_fun_internal_resolve? Fun<T> is not defined at this point... - // so mln_is_a(Fun<T>, Function) won't work. - typedef typename mln::trait::solve_unary< Fun, T >::ret impl; + template <bool set, typename Fun, typename T> + struct unary_impl_set; + + template <typename Fun, typename T> + struct unary_impl_set<false, Fun, T> : mln::Function_v2v< unary<Fun, T> > + { + typedef mln_trait_nunary(Fun, T) impl; + + typedef typename impl::argument argument; typedef typename impl::result result; + typedef mln_trait_fun_param(impl) param_; + typedef mlc_if(mlc_equal(param_, void), impl, param_) init_param; + + unary_impl_set() {} + + unary_impl_set(const init_param& p) : impl_(p) {} + + result operator () (const argument& value) const + { + return this->impl_.read(value); + } + + protected: + impl impl_; + }; + + template <typename Fun, typename T> + struct unary_impl_set<true, Fun, T> : unary_impl_set<false, Fun, T> + { + typedef unary_impl_set<false, Fun, T> super; + typedef typename super::impl impl; + typedef typename impl::argument argument; + typedef typename impl::result result; typedef typename impl::lvalue lvalue; typedef internal::unary_modifier<impl> lresult; - result operator () (const argument& value) const + unary_impl_set() {} + unary_impl_set(const typename super::init_param& p) : super(p) {} + + void set(lvalue l, const result& r) const { - return impl::read(value); + this->impl_.write(l, r); } lresult operator () (argument& value) const { - return lresult(value); + return lresult(this->impl_, value); } - void set(lvalue l, const result& r) const + using super::operator(); + }; + + template <bool set, typename Fun, typename T> + struct unary_impl_param; + + template <typename Fun, typename T> + struct unary_impl_param<false, Fun, T> + : impl::unary_impl_set<mln_trait_fun_is_assignable_(mln_trait_nunary(Fun, T))::value, Fun, T> { - impl::write(l, r); - } + typedef impl::unary_impl_set<mln_trait_fun_is_assignable_(mln_trait_nunary(Fun, T))::value, Fun, T> super; + + unary_impl_param() {} + unary_impl_param(const typename super::init_param& p) : super(p) {} }; - } - namespace trait + template <typename Fun, typename T> + struct unary_impl_param<true, Fun, T> + : unary_impl_param<false, Fun, T> { + typedef unary_impl_param<false, Fun, T> super; - namespace fun + unary_impl_param() {} + unary_impl_param(const typename super::init_param& p) : super(p) {} + + typedef typename super::param_ param; + + void init(const param& p) + { + this->impl_.init(p); + } + }; + + } // end of namespace mln::fun::spe::impl + + template <typename Fun, typename T> + struct unary + : impl::unary_impl_param<mln_trait_fun_is_parametrable_(mln_trait_nunary(Fun, T))::value, Fun, T> { + typedef impl::unary_impl_param<mln_trait_fun_is_parametrable_(mln_trait_nunary(Fun, T))::value, Fun, T> + super; + + unary() {} + unary(const typename super::init_param& p) : super(p) {} + + using super::operator(); + }; + + } // end of namespace mln::fun::spe - /// Find correct implementation template <typename F> - struct is_assignable + struct unary; + + namespace internal + { + template <typename T> + struct unary_with {}; + + template <bool has_param, typename M, typename T> + struct unary_with_param_helper; + + template <typename M, typename T> + struct unary_with_param_helper<false, M, T> + { + typedef mln::fun::spe::unary<M, T> function; + + static function inst(const M&) + { + return function(); + }; + + }; + + template <typename M, typename T> + struct unary_with_param_helper<true, M, T> { - typedef metal::true_ ret; + typedef mln::fun::spe::unary<M, T> function; + + static function inst(const M& m) + { + return function(m.parameter()); + }; + }; + template <typename M, typename T> + struct unary_with_helper : unary_with_param_helper<mln_trait_fun_is_parametrable_(M)::value, M, T> + { + typedef unary_with_param_helper<mln_trait_fun_is_parametrable_(M)::value, M, T> super; + typedef typename super::function function; + + static typename function::result call(const M& m, const T& x) + { + function f(super::inst(m)); + return f(x); } + static typename function::lresult lcall(const M& m, T& x) + { + function f(super::inst(m)); + return f(x); } - namespace meta + static void set(const M& m, typename function::lvalue v, const T& x) { - template <template <class> class F> - struct unary : mln::Meta_Function< unary<F> > + function f(super::inst(m)); + f.set(v, x); + } + + }; + + } + + template <typename F> + struct unary: mln::Meta_Function_v2v< F > { + + template <typename T> + struct with { + typedef mln_trait_nunary(internal::unary_with<F>, T) impl; + typedef typename impl::function ret; + }; + template <typename T> - typename F<T>::result operator()(const T& v) const + typename with<T>::ret::result operator()(const T& v) const { - F<T> tmp; - return tmp(v); + return with<T>::impl::call(exact(*this), v); } template <typename T> - typename F<T>::lresult operator()(T& v) const + typename with<T>::ret::lresult operator()(T& v) const { - F<T> tmp; - return tmp(v); + return with<T>::impl::lcall(exact(*this), v); } - template <typename T> - struct with + template <typename T, typename R> + void set(T& v, const R& r) const { - typedef F<T> ret; + with<T>::impl::set(exact(*this), v, r); + } + }; + + template <typename F, typename P> + struct unary_param: unary<F> + { + typedef P param; + + unary_param() {}; + unary_param(const param& p) : p_(p) {}; + + void init(const param& p) + { + p_ = p; + } + + param& parameter() + { + return p_; + } + + const param& parameter() const + { + return p_; + } + + protected: + param p_; }; + + template <typename F> + struct unary_param<F, F>: unary<F> + { + typedef F param; + + void init(const param& p) + { + exact(*this) = p; + } + + param& parameter() + { + return exact(*this); + } + + const param& parameter() const + { + return exact(*this); + } + + }; + + } // end of namespace mln::fun + + namespace trait + { + + namespace next + { + + // Any type + template <typename F, typename T> + struct set_unary_< mln::fun::internal::unary_with<F>, mln::Object, T> + { + typedef mln::fun::internal::unary_with_helper<F, T> ret; + }; + + // Meta Function + template <typename F, typename G> + struct set_unary_< mln::fun::internal::unary_with<F>, mln::Meta_Function, G> + { + // FIXME: Workaround for cyclic references (unary -> unary_with -> compose -> unary) + template <typename T> + struct identity + { + typedef T ret; + }; + + typedef set_unary_ ret; + typedef typename identity<mln::fun::compose>::ret::template with<F, G>::ret function; + + static typename function::result call(const F& f, const G& g) + { + function tmp; + return tmp(f, g); } + }; } + } template <typename Impl> std::ostream& operator << (std::ostream& o, const mln::fun::internal::unary_modifier<Impl>& m) @@ -129,4 +352,6 @@ return o << m.to_result(); } +} // end of namespace mln + #endif /* ! UNARY_HH */ Index: trunk/milena/sandbox/fred/fun/assignability.hh =================================================================== --- trunk/milena/sandbox/fred/fun/assignability.hh (revision 0) +++ trunk/milena/sandbox/fred/fun/assignability.hh (revision 3519) @@ -0,0 +1,103 @@ +#ifndef ASSIGNABILITY_HH +# define ASSIGNABILITY_HH + +# include <mln/metal/bexpr.hh> +# include <mln/metal/if.hh> + +#define mln_trait_fun_is_assignable(Fun) typename mln::trait::fun::is_assignable< Fun >::ret +#define mln_trait_fun_is_assignable_(Fun) mln::trait::fun::is_assignable< Fun >::ret +#define mln_trait_fun_is_assignable__1comma(A, B) mln_trait_fun_is_assignable(A, B) +#define mln_trait_fun_is_assignable__1comma_(A, B) mln_trait_fun_is_assignable_(A, B) + +#define mln_trait_fun_is_parametrable(Fun) typename mln::trait::fun::is_parametrable< Fun >::ret +#define mln_trait_fun_is_parametrable_(Fun) mln::trait::fun::is_parametrable< Fun >::ret + +#define mln_trait_fun_lvalue(Fun) typename mln::trait::fun::get_lvalue< Fun >::ret +#define mln_trait_fun_param(Fun) typename mln::trait::fun::get_param< Fun >::ret +namespace mln +{ + + namespace trait + { + + namespace fun + { + + namespace internal + { + + namespace introspect + { + + template <typename T> + struct except_void_t + { + typedef void ret; + }; + + template <> + struct except_void_t<void>; + + template <typename T, typename V> + struct has_lvalue_t + { + typedef metal::false_ ret; + typedef void type; + }; + + template <typename T> + struct has_lvalue_t<T, typename except_void_t<typename T::lvalue>::ret> + { + typedef metal::true_ ret; + typedef typename T::lvalue type; + }; + + template <typename T, typename V> + struct has_param_t + { + typedef metal::false_ ret; + typedef void type; + }; + + template <typename T> + struct has_param_t<T, typename except_void_t<typename T::param>::ret> + { + typedef metal::true_ ret; + typedef typename T::param type; + }; + + } + + } // end of namespace mln::trait::fun::internal + + template <typename F> + struct is_assignable + { + typedef typename internal::introspect::has_lvalue_t<F, void>::ret ret; + }; + + template <typename F> + struct is_parametrable + { + typedef typename internal::introspect::has_param_t<F, void>::ret ret; + }; + + template <typename F> + struct get_lvalue + { + typedef typename internal::introspect::has_lvalue_t<F, void>::type ret; + }; + + template <typename F> + struct get_param + { + typedef typename internal::introspect::has_param_t<F, void>::type ret; + }; + + } // end of namespace mln::trait::fun + + } // end of namespace mln::trait + +} // end of namespace mln + +#endif // ! ASSIGNABILITY_HH \ No newline at end of file Index: trunk/milena/sandbox/fred/fun/composition.hh =================================================================== --- trunk/milena/sandbox/fred/fun/composition.hh (revision 0) +++ trunk/milena/sandbox/fred/fun/composition.hh (revision 3519) @@ -0,0 +1,210 @@ +#ifndef COMPOSITION_HH +# define COMPOSITION_HH + +# include "unary.hh" +# include "binary.hh" + +namespace mln +{ + // Composition + namespace fun + { + + namespace internal + { + + // Compositions may take this has initialization parameter + template <typename F, typename G> + struct composition_param + { + composition_param(const F& f, const G& g) : f_(f), g_(g) {} + composition_param() {} + + F f_; + G g_; + }; + + // Composition types... + template <template <class> class CatF, typename F, + template <class> class CatG, typename G> + struct composition; + + // Meta + template <typename F, typename G> + struct composition<mln::Meta_Function_v2v, F, mln::Meta_Function_v2v, G> + : mln::fun::unary_param< composition<mln::Meta_Function_v2v, F, mln::Meta_Function_v2v, G>, composition_param<F, G> > + { + typedef mln::fun::unary_param< composition<mln::Meta_Function_v2v, F, mln::Meta_Function_v2v, G>, composition_param<F, G> > super; + + composition() {}; + composition(const typename super::param& p) : super(p) {}; + + typedef composition exact_type; + }; + + template <typename F, typename G> + struct composition<mln::Meta_Function_v2v, F, mln::Meta_Function_vv2v, G> + : mln::fun::binary_param< composition<mln::Meta_Function_v2v, F, mln::Meta_Function_vv2v, G>, composition_param<F, G> > + { + typedef mln::fun::binary_param< composition<mln::Meta_Function_v2v, F, mln::Meta_Function_vv2v, G>, composition_param<F, G> > super; + + composition() {}; + composition(const typename super::param& p) : super(p) {}; + + typedef composition exact_type; + }; + + // Concrete + template <typename F, typename G> + struct composition<mln::Meta_Function_v2v, F, mln::Function_v2v, G> + { + typedef mln::fun::spe::unary< composition<mln::Meta_Function_v2v, F, mln::Function_vv2v, G>, typename G::argument> exact_type; + }; + + template <typename F, typename G> + struct composition<mln::Meta_Function_v2v, F, mln::Function_vv2v, G> + { + typedef mln::fun::spe::binary< composition<mln::Meta_Function_v2v, F, mln::Function_vv2v, G>, + typename G::argument1, typename G::argument2> exact_type; + }; + + // Unary compositions implementation inherit from composition_unary_impl... + template <bool has_lvalue, typename F, typename F_spe, typename G, typename G_spe> + struct composition_unary_impl_helper; + + template <typename F, typename F_spe, typename G, typename G_spe> + struct composition_unary_impl_helper<false, F, F_spe, G, G_spe> + { + typedef typename G_spe::argument argument; + typedef typename F_spe::result result; + typedef composition_param<F, G> param; + + composition_unary_impl_helper() {} + composition_unary_impl_helper(const param& p) : f_(p.f_), g_(p.g_) {} + + void init(const param& p) + { + f_ = p.f_; + g_ = p.g_; + } + + result read(const argument& x) const + { + return this->f_(this->g_(x)); + } + + protected: + F f_; + G g_; + }; + + template <typename F, typename F_spe, typename G, typename G_spe> + struct composition_unary_impl_helper<true, F, F_spe, G, G_spe> + : composition_unary_impl_helper<false, F, F_spe, G, G_spe> + { + typedef composition_unary_impl_helper<false, F, F_spe, G, G_spe> super; + typedef typename G_spe::lvalue lvalue; + + composition_unary_impl_helper() {} + composition_unary_impl_helper(const typename super::param& p) : super(p) {} + + void write(lvalue l, const typename super::result& x) const + { + typename G_spe::result r(this->g_(l)); + + this->f_.set(r, x); + this->g_.set(l, r); + } + }; + + template <typename F, typename F_spe, typename G, typename G_spe> + struct composition_unary_impl + : composition_unary_impl_helper<mln_trait_fun_is_assignable_(G_spe)::value, F, F_spe, G, G_spe> + { + typedef composition_unary_impl_helper<mln_trait_fun_is_assignable_(G_spe)::value, F, F_spe, G, G_spe> super; + + composition_unary_impl() {} + composition_unary_impl(const typename super::param& p) : super(p) {} + }; + + // Binary compositions implementation inherit from composition_binary_inherit... + template <typename F, typename F_spe, typename G, typename G_spe> + struct composition_binary_impl + { + typedef typename G_spe::argument1 argument1; + typedef typename G_spe::argument2 argument2; + typedef typename F_spe::result result; + typedef composition_param<F, G> param; + + composition_binary_impl() {} + composition_binary_impl(const param& p) : f_(p.f_), g_(p.g_) {} + + void init(const param& p) + { + f_ = p.f_; + g_ = p.g_; + } + + result read(const argument1& a, const argument2& b) const + { + return this->f_(this->g_(a, b)); + } + + protected: + F f_; + G g_; + }; + + } + + } + + namespace trait + { + + namespace next + { + + template <typename F, typename G, typename T> + struct set_precise_unary_<mln::fun::internal::composition<mln::Meta_Function_v2v, F, mln::Meta_Function_v2v, G>, T> + { + typedef typename G::template with<T>::ret G_fun; + typedef typename F::template with<typename G_fun::result>::ret F_fun; + + typedef mln::fun::internal::composition_unary_impl<F, F_fun, G, G_fun> ret; + }; + + template <typename F, typename G, typename T1, typename T2> + struct set_precise_binary_<mln::fun::internal::composition<mln::Meta_Function_v2v, F, mln::Meta_Function_vv2v, G>, T1, T2> + { + typedef typename G::template with<T1, T2>::ret G_fun; + typedef typename F::template with<typename G_fun::result>::ret F_fun; + + typedef mln::fun::internal::composition_binary_impl<F, F_fun, G, G_fun> ret; + }; + + template <typename F, typename G> + struct set_precise_unary_<mln::fun::internal::composition<mln::Meta_Function_v2v, F, mln::Function_v2v, G>, + typename G::argument> + { + typedef typename F::template with<typename G::result>::ret F_fun; + + typedef mln::fun::internal::composition_unary_impl<F, F_fun, G, G> ret; + }; + + template <typename F, typename G> + struct set_precise_binary_<mln::fun::internal::composition<mln::Meta_Function_v2v, F, mln::Meta_Function_vv2v, G>, + typename G::argument1, typename G::argument2> + { + typedef typename F::template with<typename G::result>::ret F_fun; + + typedef mln::fun::internal::composition_binary_impl<F, F_fun, G, G> ret; + }; + + } + + } + +} + +#endif /* ! COMPOSITION_HH */ \ No newline at end of file Index: trunk/milena/sandbox/fred/fun/abs.hh =================================================================== --- trunk/milena/sandbox/fred/fun/abs.hh (revision 3518) +++ trunk/milena/sandbox/fred/fun/abs.hh (revision 3519) @@ -22,7 +22,6 @@ typedef set_unary_ ret; typedef T result; typedef T argument; - typedef T& lvalue; static result read(const argument& x) { Index: trunk/milena/sandbox/fred/fun/compose.hh =================================================================== --- trunk/milena/sandbox/fred/fun/compose.hh (revision 0) +++ trunk/milena/sandbox/fred/fun/compose.hh (revision 3519) @@ -0,0 +1,71 @@ +#ifndef COMPOSE_HH +# define COMPOSE_HH + +# include "composition.hh" + +namespace mln +{ + // Composition + namespace fun + { + struct compose : binary<compose> {}; + + namespace internal + { + + template <template <class> class CatF, typename F, template <class> class CatG, typename G> + struct compose_helper + { + typedef F argument1; + typedef G argument2; + + typedef typename composition<CatF, F, CatG, G>::exact_type result; + typedef typename result::param param; + + static result read(const F& f, const G& g) + { + return result(param(f, g)); + } + }; + + } + } + + namespace trait + { + + namespace next + { + + // All kinds of supported compositions (meta : unary) with (meta or not : unary or binary) + template <typename F, typename G> + struct set_binary_< mln::fun::compose, mln::Meta_Function_v2v, F, mln::Meta_Function_v2v, G> + { + typedef mln::fun::internal::compose_helper<mln::Meta_Function_v2v, F, mln::Meta_Function_v2v, G> ret; + }; + + template <typename F, typename G> + struct set_binary_< mln::fun::compose, mln::Meta_Function_v2v, F, mln::Meta_Function_vv2v, G> + { + typedef mln::fun::internal::compose_helper<mln::Meta_Function_v2v, F, mln::Meta_Function_vv2v, G> ret; + }; + + template <typename F, typename G> + struct set_binary_< mln::fun::compose, mln::Meta_Function_v2v, F, mln::Function_v2v, G> + { + typedef mln::fun::internal::compose_helper<mln::Meta_Function_v2v, F, mln::Function_v2v, G> ret; + }; + + template <typename F, typename G> + struct set_binary_< mln::fun::compose, mln::Meta_Function_v2v, F, mln::Function_vv2v, G> + { + typedef mln::fun::internal::compose_helper<mln::Meta_Function_v2v, F, mln::Function_vv2v, G> ret; + }; + + } + + } + +} + +#endif /* ! COMPOSE_HH */ \ No newline at end of file Index: trunk/milena/sandbox/fred/fun/nsolve.hh =================================================================== --- trunk/milena/sandbox/fred/fun/nsolve.hh (revision 0) +++ trunk/milena/sandbox/fred/fun/nsolve.hh (revision 3519) @@ -0,0 +1,152 @@ +// Copyright (C) 2006, 2008 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef MLN_TRAIT_NSOLVE_HH +# define MLN_TRAIT_NSOLVE_HH + +/*! + * \file mln/trait/nsolve.hh + * + * \brief FIXME + * + * + */ + +# include <mln/core/category.hh> +# include <mln/metal/equal.hh> +# include <mln/metal/if.hh> +# include <mln/metal/ret.hh> +# include <mln/trait/solve.hh> + + +// FIXME: Just for the record (use it...) + +# ifndef MLN_DEBUG_TRAITS +# endif // ! MLN_DEBUG_TRAITS + + +# define mln_trait_nunary(Name, T) typename mln::trait::next::solve_unary< Name, T >::ret +# define mln_trait_nunary_(Name, T) mln::trait::next::solve_unary< Name, T >::ret + +# define mln_trait_nbinary(Name, T1, T2) typename mln::trait::next::solve_binary< Name, T1, T2 >::ret +# define mln_trait_nbinary_(Name, T1, T2) mln::trait::next::solve_binary< Name, T1, T2 >::ret + + + +namespace mln +{ + + namespace trait + { + + namespace next + { + + // Unary case. + + + template < typename Name, + typename T > + struct set_precise_unary_ + { + typedef undefined ret; + }; + + + template < typename Name, + template <class> class Category_T, typename T > + struct set_unary_ + { + typedef undefined ret; + }; + + template < typename Name, + typename T > + struct set_unary_< Name, Unknown, T > // Blocker; top of inheritance. + { + typedef not_found ret; + }; + + + + + // Binary case. + + + template < typename Name, + typename L, + typename R > + struct set_precise_binary_ + { + typedef undefined ret; + }; + + + template < typename Name, + template <class> class Category_L, typename L, + template <class> class Category_R, typename R > + struct set_binary_ + { + typedef undefined ret; + }; + + template < typename Name, + typename L, + template <class> class Category_R, typename R > + struct set_binary_< Name, Unknown, L, Category_R, R > // Left blocker. + { + typedef not_found ret; + }; + + template < typename Name, + template <class> class Category_L, typename L, + typename R > + struct set_binary_< Name, Category_L, L, Unknown, R > // Right blocker. + { + typedef not_found ret; + }; + + template < typename Name, + typename L, + typename R > + struct set_binary_< Name, Unknown, L, Unknown, R > // Blocker. + { + typedef not_found ret; + }; + + } // end of namespace mln::trait::next + + } // end of namespace mln::trait + +} // end of namespace mln + + +# include "nsolve_unary.hh" +# include "nsolve_binary.hh" + + +#endif // ! MLN_TRAIT_NSOLVE_HH Index: trunk/milena/sandbox/fred/fun/cos.cc =================================================================== --- trunk/milena/sandbox/fred/fun/cos.cc (revision 0) +++ trunk/milena/sandbox/fred/fun/cos.cc (revision 3519) @@ -0,0 +1,34 @@ +// Meta functions test +#include "cos.hh" +#include "compose.hh" + +#include <iostream> + +#define dbg_print(val) std::cout << #val << "\n\t -> \t" << (val) << std::endl +int main() +{ + mln::fun::cos cos; + mln::fun::compose compose; + + double x; + dbg_print(cos(compose)(cos,cos)(x) = 0.857553); + dbg_print(x); + dbg_print(cos(compose)(cos,cos)(0.)); + + // COS + { + mln_invariant(cos(0.) == 1.); + dbg_print(cos(0.)); + dbg_print(cos(mln::math::acos(0.5))); + } + + // COS + { + double x; + dbg_print(cos(x) = 1.); + mln_invariant(cos(x) == 1.); + dbg_print(x); + } + + std::cout << "Ok." << std::endl; +} \ No newline at end of file Index: trunk/milena/sandbox/fred/fun/nsolve_binary.hh =================================================================== --- trunk/milena/sandbox/fred/fun/nsolve_binary.hh (revision 0) +++ trunk/milena/sandbox/fred/fun/nsolve_binary.hh (revision 3519) @@ -0,0 +1,302 @@ +// Copyright (C) 2006, 2008, 2009 EPITA Research and Development +// Laboratory (LRDE) +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. +#ifndef MLN_TRAIT_NSOLVE_BINARY_HH +# define MLN_TRAIT_NSOLVE_BINARY_HH + +/// \file mln/trait/solve_binary.hh +/// +/// FIXME + +# include <mln/core/category.hh> +# include <mln/core/routine/exact.hh> +# include <mln/metal/equal.hh> +# include <mln/metal/if.hh> +# include <mln/metal/ret.hh> +# include "nsolve.hh" + + +// FIXME: Just for the record (use it...) + +# ifndef MLN_DEBUG_TRAITS +# endif // ! MLN_DEBUG_TRAITS + + + +namespace mln +{ + + namespace trait + { + + namespace next + { + + namespace internal + { + + + template < typename Name, + typename Category_L, typename L, + typename Category_R, typename R > + struct trait_set_binary_; + + template < typename Name, + template <class> class Category_L, typename _l, typename L, + template <class> class Category_R, typename _r, typename R > + struct trait_set_binary_< Name, + Category_L<_l>, L, + Category_R<_r>, R > + { + typedef typename mln::trait::next::set_binary_<Name, + Category_L, L, + Category_R, R>::ret ret; + }; + + + // triplet_ret_ + + template < unsigned i_L_, unsigned i_R_, typename ret_ > + struct triplet_ + { + typedef ret_ ret; + }; + + + // merge_triplets_ + + template < typename L_trp, typename R_trp > + struct merge_triplets_; + + template < unsigned L_i_L, unsigned L_i_R, typename L_ret, + unsigned R_i_L, unsigned R_i_R, typename R_ret > + struct merge_triplets_< triplet_<L_i_L, L_i_R, L_ret>, + triplet_<R_i_L, R_i_R, R_ret> > + { + typedef metal::bool_<(L_i_L <= R_i_L && L_i_R <= R_i_R)> take_L; + typedef metal::bool_<(R_i_L <= L_i_L && R_i_R <= L_i_R)> take_R; + typedef metal::or_<take_L, take_R> ok; + typedef typename metal::if_< metal::and_<ok, take_L>, + triplet_<L_i_L, L_i_R, L_ret>, + typename metal::if_< metal::and_<ok, take_R>, + triplet_<R_i_L, R_i_R, R_ret>, + triplet_<0,0, not_found> >::ret >::ret ret; + }; + + template < unsigned i_L, unsigned i_R, typename LR_ret > + struct merge_triplets_< triplet_<i_L, i_R, LR_ret>, + triplet_<i_L, i_R, LR_ret> > + { + typedef triplet_<i_L, i_R, LR_ret> ret; + }; + + + template < unsigned L_i_L, unsigned L_i_R, unsigned L_i_max, + unsigned R_i_L, unsigned R_i_R, unsigned R_i_max > + // L_i_max and R_i_max differ + struct helper_merge_triplets_same_ret_ + { + // The winning couple between L_* and R_* is the one which + // maximum index is the smallest; for instance, with: + // left branch giving L_i_L = 5 and L_i_R = 1 so L_i_max = 5 + // right branch giving L_i_L = 3 and L_i_R = 4 so R_i_max = 4 + // the right branch wins. + enum { i_L = (L_i_max < R_i_max ? L_i_L : R_i_L), + i_R = (L_i_max < R_i_max ? L_i_R : R_i_R) }; + }; + + template < unsigned L_i_L, unsigned L_i_R, unsigned i_max, + unsigned R_i_L, unsigned R_i_R > + // L_i_max is equal to R_i_max + struct helper_merge_triplets_same_ret_< L_i_L, L_i_R, i_max, + R_i_L, R_i_R, i_max > + { + // The winning couple is the one with the minimum index. + enum { L_i_min = (L_i_L < L_i_R ? L_i_L : L_i_R), + R_i_min = (R_i_L < R_i_R ? R_i_L : R_i_R), + i_L = (L_i_min < R_i_min ? L_i_L : R_i_L), + i_R = (L_i_min < R_i_min ? L_i_R : R_i_R) }; + }; + + + template < unsigned L_i_L, unsigned L_i_R, typename LR_ret, + unsigned R_i_L, unsigned R_i_R > + struct merge_triplets_< triplet_<L_i_L, L_i_R, LR_ret>, + triplet_<R_i_L, R_i_R, LR_ret> > + { + typedef helper_merge_triplets_same_ret_< L_i_L, L_i_R, (L_i_L > L_i_R ? L_i_L : L_i_R), + R_i_L, R_i_R, (R_i_L > R_i_R ? R_i_L : R_i_R) > helper; + typedef triplet_<helper::i_L, helper::i_R, LR_ret> ret; + }; + + template < unsigned L_i_L, unsigned L_i_R, typename L_ret > + struct merge_triplets_< triplet_<L_i_L, L_i_R, L_ret>, + triplet_< 0, 0, not_found> > + { + typedef triplet_<L_i_L, L_i_R, L_ret> ret; + }; + + template < unsigned R_i_L, unsigned R_i_R, typename R_ret > + struct merge_triplets_< triplet_< 0, 0, not_found>, + triplet_<R_i_L, R_i_R, R_ret> > + { + typedef triplet_<R_i_L, R_i_R, R_ret> ret; + }; + + template <> // To disambiguate. + struct merge_triplets_< triplet_<0, 0, not_found>, + triplet_<0, 0, not_found> > + { + typedef triplet_<0u,0u, not_found> ret; + }; + + + + // Fwd decl. + template < typename Name, + unsigned i_L, typename Category_L, typename L, + unsigned i_R, typename Category_R, typename R > + struct get_binary_; + + + template < typename user_ret, /* != not_found and != undefined */ + typename Name, + unsigned i_L, typename Category_L, typename L, + unsigned i_R, typename Category_R, typename R > + struct helper_get_binary_ + { + typedef triplet_< i_L, i_R, user_ret > ret; // The user has defined 'ret' so we return it. + }; + + template < typename Name, + unsigned i_L, typename Category_L, typename L, + unsigned i_R, typename Category_R, typename R > + struct helper_get_binary_< /* user_ret == */ not_found, + Name, i_L, Category_L, L, i_R, Category_R, R > + { + typedef triplet_< 0, 0, not_found > ret; // End of search due to a blocker; 'ret' is not found. + }; + + + template < typename Name, + unsigned i_L, typename Category_L, typename L, + unsigned i_R, typename Category_R, typename R > + struct helper_get_binary_< /* user_ret == */ undefined, + Name, i_L,Category_L, L, i_R,Category_R, R > + { + // No user definition for 'ret' so treillis construction in a static recursive way. + + // FIXME: We *do* need to handle this search with a priority! + // FIXME: for a result can be found in both branches... + + typedef typename mln::internal::super_category_< Category_L, L >::ret Super_Category_L; + typedef typename mln::internal::super_category_< Category_R, R >::ret Super_Category_R; + + typedef get_binary_< Name, + i_L + 1, Super_Category_L, L, + i_R, Category_R, R > L_branch; + typedef mlc_ret(L_branch) L_trp; + + typedef get_binary_< Name, + i_L, Category_L, L, + i_R + 1, Super_Category_R, R > R_branch; + typedef mlc_ret(R_branch) R_trp; + + typedef typename merge_triplets_< L_trp, R_trp >::ret ret; + }; + + + template < typename Name, + unsigned i_L, typename Category_L, typename L, + unsigned i_R, typename Category_R, typename R > + struct get_binary_ + { + typedef typename trait_set_binary_<Name, Category_L,L, + Category_R,R>::ret user_ret; // First get 'user_ret' + typedef helper_get_binary_<user_ret, Name, i_L,Category_L,L, + i_R,Category_R,R> helper; // Set the helper to make a decision. + typedef mlc_ret(helper) ret; // Return a triplet. + }; + + + template < typename precise_ret, + typename Name, + typename Category_L, typename L, + typename Category_R, typename R > + struct helper_choose_binary_wrt_ /* precise_ret != undefined */ + { + typedef precise_ret ret; // -> A precise ret has been defined so it is it. + }; + + template < typename Name, + typename Category_L, typename L, + typename Category_R, typename R > + struct helper_choose_binary_wrt_< /* precise_ret == */ undefined, + Name, Category_L, L, Category_R, R > + { + typedef typename get_binary_< Name, + 0, Category_L, L, + 0, Category_R, R >::ret triplet; // Browse upwards the category inheritance + typedef mlc_ret(triplet) ret; // to fetch ret from 'get_binary_'s. + }; + + + template < typename Name, + typename Category_L, typename L, + typename Category_R, typename R > + struct helper_solve_binary_ + { + typedef typename set_precise_binary_<Name, L, R>::ret precise_ret; /* undefined or not (?) */ + typedef helper_choose_binary_wrt_<precise_ret, Name, Category_L,L, Category_R,R> helper; + typedef mlc_ret(helper) ret; + }; + + } // end of namespace mln::trait::internal + + + // FIXME: Postfix solve_binary with a '-'(?) + template < typename Name, + typename L_, + typename R_ > + struct solve_binary + { + typedef mln_exact(L_) L; + typedef mln_exact(R_) R; + typedef typename mln::category<L>::ret Category_L; + typedef typename mln::category<R>::ret Category_R; + typedef internal::helper_solve_binary_< Name, Category_L, L, Category_R, R > meta_code; + typedef typename meta_code::ret ret; + }; + + } // end of namespace mln::trait::next + + } // end of namespace mln::trait + +} // end of namespace mln + + +#endif // ! MLN_TRAIT_NSOLVE_BINARY_HH Index: trunk/milena/sandbox/fred/fun/fun.cc =================================================================== --- trunk/milena/sandbox/fred/fun/fun.cc (revision 3518) +++ trunk/milena/sandbox/fred/fun/fun.cc (revision 3519) @@ -27,6 +27,10 @@ dbg_print(abs(-1)); dbg_print(abs(-3.1415926535)); + int x = 1; + abs(x) = 2; + abs.set(x, 2); + // INC mln_invariant(inc(-1) == 0); dbg_print(inc(-1)); @@ -48,6 +52,7 @@ v[2] = 0; dbg_print(v); dbg_print(l1(v)); +// dbg_print(cos(l1)(v)); dbg_print(l2(v)); dbg_print(linfty(v)); Index: trunk/milena/sandbox/fred/fun/thru_morpher.hh =================================================================== --- trunk/milena/sandbox/fred/fun/thru_morpher.hh (revision 3518) +++ trunk/milena/sandbox/fred/fun/thru_morpher.hh (revision 3519) @@ -135,6 +135,7 @@ public: /// Type returned by the read-write pixel value operator. +// typedef typename F::template lresult<typename F::argument>::ret lvalue; typedef typename F::lresult lvalue; using thru_image_read<I,F>::operator();
participants (1)
-
Frederic Bour