Re: [sigc] Fixing lambda bugs
- From: Murray Cumming <murrayc murrayc com>
- To: kenelson8 comcast net
- Cc: libsigc-list gnome org
- Subject: Re: [sigc] Fixing lambda bugs
- Date: Fri, 02 Jan 2009 12:52:08 +0100
On Wed, 2008-12-31 at 07:26 +0000, kenelson8 comcast net wrote:
> Murray,
>
> The key problem is the usual problem with references and const references.
This is still rather vague.
> Although I and probably a few others have suggested adding a template
> pattern to pass arguments through as reference without forcing a type check
> (ie. template <class &T> void foo(T t) {} where T will be any reference, const
> reference, volitile const reference, etc.), it was summarily rejected.
I doubt that it was "summarily rejected". Do you have a URL?
> However,
> recently I looked through the proposed changes for the next version.
What "proposed changes" do you mean?
> Still no action as far as I can see. However, one of changes did inspire me to
> update my print format class which got me working on the problem again. That
> was that I could use a variodic template pattern. As part of that work I built a
> wrapper to work around the problem.
The rest of this is rather difficult for me to parse. Are you Karl
Nelson, by any chance?
As usual, the best way to proceed is probably to create a small test
case that shows what the actual problem is. Please put this in bugzilla.
You have not yet mentioned a specific class whose API or ABI you would
like to change. If you can't name them now, then I guess we can look at
a patch. Note also that an ABI-breaking libsigc++ 3.0 (or suchlike) is
entirely possible at some time.
> I have two options that can fix the defect with argument copying, some of the
> operator returns not promoting properly, and improper function of equality operators.
> 1) Apply the same pattern in my variodic template library to this problem.
> 2) Convert the lambda library to use the variodic template library.
>
> In either case the outward library interface should have no changes what-so-ever.
> However, the second option will gut the library entirely. I am slightly more interested
> in the second than the first in that I don't remember (or perhaps there have been
> patches applied) such that figuring out where to perform the surgery for option 1 will
> take a while. Then again option 2 may have similar problems.
>
> In either case if I cut too deeply in the internals it will break users that wrote a function
> that a lambda without a closure (a very bad idea) or a user that wrote their own internal
> to use lambda (some of the extension libraries may have done something like this).
>
> To give you a better idea which way may be best I have inclosed a sample for the
> variodic template library so that this isn't quite so cryptic. Significant differences would
> be that variodic functions use execute to avoid that sun bug with operator() and lambda
> would get variodic_function<T_func> as a base class.
You forget to attach that. But I'd still like to start with a test case
that shows what problem you are trying to solve.
> The type promotion I have working in practice, but I will need to plan how to
> apply it current lambda library. I have also attached a sample of that. This one may have
> architecture issues as int*int is not actually an int but may be a int64_t so there are
> a fair number of edge cases to consider.
>
> Does this help clarify?
>
> --Karl
>
> -------------- Original message ----------------------
> From: Murray Cumming <murrayc murrayc com>
> > On Fri, 2008-12-12 at 02:28 +0000, kenelson8 comcast net wrote:
> > > Hello all,
> > >
> > > I see there are some outstanding bugs in the lambda section. I think that I
> > > can fix some of them along with some of the FIXME sections, however, I
> > > am concerned with the level of changes that may be required. Is anyone
> > > using the lambda?
> >
> > Probably, yes.
> >
> > > Also is anyone connecting into the internal classes which
> > > will likely get broken by a big change?
> >
> > Can you be more specific? Then we can judge what a change there would
> > affect. If it's obviously a private internal thing then there's no
> > problem with breaking it.
> >
> > Murray.
> >
>
> =======================================================
>
> #include <iostream>
>
> struct variodic0
> {
> typedef variodic0 next_type;
> typedef void value1_type;
> next_type& next() { return *this; }
> };
> variodic0 variodic0_instance;
>
> template <class T1>
> struct variodic1 {
> typedef variodic0 next_type;
> typedef T1 value1_type;
> variodic1(value1_type& p1)
> : value_(p1) {}
> value1_type& value() const {return value_; }
> value1_type& value1() const { return value_ ;}
> next_type& next() const { return variodic0_instance; }
> private:
> value1_type& value_;
> };
>
> template <class T1, class T2>
> struct variodic2 {
> typedef variodic1<T2> next_type;
> typedef T1 value1_type;
> typedef T2 value2_type;
> variodic2(T1& p1, T2& p2)
> : value_(p1), next_(p2){}
> value1_type& value() const {return value_; }
> value1_type& value1() const {return value_; }
> value2_type& value2() const {return next_.value1(); }
> next_type &next() const {return const_cast<next_type&>(next_); }
>
> private:
> value1_type& value_;
> next_type next_;
> };
>
> template <class T1, class T2, class T3>
> struct variodic3 {
> typedef variodic2<T2,T3> next_type;
> typedef T1 value1_type;
> typedef T2 value2_type;
> typedef T3 value3_type;
>
> variodic3(T1& p1, T2& p2, T3& p3)
> : value_(p1), next_(p2,p3){}
> value1_type& value() const {return value_; }
> value1_type& value1() const {return value_; }
> value2_type& value2() const {return next_.value1(); }
> value3_type& value3() const {return next_.value2(); }
> next_type &next() const {return const_cast<next_type&>(next_); }
>
> private:
> value1_type& value_;
> next_type next_;
> };
>
> /* What does a variodic_function require?
>
> class myfunc_implementation
> {
> public:
> // 1) This indicates the result if called with 0 arguments
> typedef void result_type;
>
> // 2) This indicates the type when multople arguments are called
> // This can have specialization if the type is variable
> template <typename var_args> struct deduce_result_type { typedef void typ
> e; }
>
> // 3) This is the front end for the call
> // specialize this for different number of arguments
> template <typename var_args>
> deduce_result_type<V>::type execute(const var_args& v);
> };
>
> // 4) we create a concrete type instance
> // (often the instance will be in a file and thus external in the header)
> extern variodic_function<myfunc_implementation> myfunc;
> */
>
> template<class T_f>
> struct variodic_function {
> typename T_f::result_type
> operator()();
>
> // we can keep the const for a few layers
> // 2 required
> template<class T1>
> typename T_f::template deduce_result_type<variodic1<T1> >::type
> operator()(T1& t1)
> { return func_.execute(variodic1<T1>(t1)); }
> template<class T1>
> typename T_f::template deduce_result_type<variodic1<T1> >::type
> operator()(const T1& t1)
> { return func_.execute(variodic1<const T1>(t1)); }
>
> // 2^2=4 required
> template<class T1, class T2>
> typename T_f::template deduce_result_type<variodic2<T1,T2> >::type
> operator()(T1& t1, T2& t2)
> { return func_.execute(variodic2<T1,T2>(t1,t2)); }
> template<class T1, class T2>
> typename T_f::template deduce_result_type<variodic2<T1,T2> >::type
> operator()(T1& t1, const T2& t2)
> { return func_.execute(variodic2<T1,const T2>(t1,t2)); }
> template<class T1, class T2>
> typename T_f::template deduce_result_type<variodic2<T1,T2> >::type
> operator()(const T1& t1, T2& t2)
> { return func_.execute(variodic2<const T1,T2>(t1,t2)); }
> template<class T1, class T2>
> typename T_f::template deduce_result_type<variodic2<T1,T2> >::type
> operator()(const T1& t1, const T2& t2)
> { return func_.execute(variodic2<const T1,const T2>(t1,t2)); }
>
>
> // But eventually it just doesn't work as we would need too many templates
> // this hack works, but has the downside that type deduction may be a problem
> // and overloading of foo(int, char, const string&) and foo(int, char, T&) would always
> // chose the latter (though this type of overload is fairly bad practice)
> template<class T1, class T2, class T3>
> typename T_f::template deduce_result_type<variodic3<T1,T2,T3> >::type
> operator()(const T1& t1, const T2& t2, const T3& t3)
> { return func_.execute(variodic3<T1,T2,T3>(const_cast<T1&>(t1),const_cast<T2&>
> (t2),const_cast<T3&>(t3))); }
>
> private:
> T_f func_;
> };
>
> template<class T_f>
> typename T_f::result_type variodic_function<T_f>::operator()()
> { return func_.execute(variodic0()); }
>
> // Use this if the implementation returns the same thing regardless
> template <class T_R>
> struct variodic_implementation_returns
> {
> typedef T_R result_type;
> template <class T_V> struct deduce_result_type { typedef T_R type; };
> };
>
>
> /***********************************/
>
> // Test the variodic functionality
> // (idea shamelessly stolen from the variodic template example in new standard)
>
> struct qprintf_t : public variodic_implementation_returns<void>
> {
>
> // variodic function require this method
> template <class var>
> void execute(const var& v)
> { do_work(v.value(), v.next()); }
>
> // actual method
> template <class var>
> void do_work(const char* s, var& v);
> };
>
>
> template <class var>
> void qprintf_t::do_work(const char *s, var& v)
> {
> while (*s)
> {
> if (*s=='%' && *(++s)!='%')
> {
> std::cout << v.value() ;
> do_work(*s?++s: s, v.next());
> return;
> }
> std::cout << *s++;
> }
> throw int(); // too many arguments
> }
>
> // specialization when we run out of arguments
> template <>
> void qprintf_t::do_work<variodic0>(const char *s, variodic0& v)
> {
> while (*s)
> {
> if (*s=='%' && *(++s)!='%')
> throw int(); // too few arguments
> std::cout << *s++;
> }
> }
>
> variodic_function<qprintf_t> qprintf;
>
>
> =============================================
> arithmetic_h:
>
> #ifndef _CHECK_ARITHMETIC_H__
> #define _CHECK_ARITHMETIC_H__
>
> static const int bool_code=0;
> static const int char_code=1;
> static const int uchar_code=1;
> static const int short_code=2;
> static const int ushort_code=2;
> static const int int_code=3;
> static const int uint_code=3;
> static const int long_code=4;
> static const int ulong_code=4;
> static const int float_code=5;
> static const int double_code=6;
> static const int other_code=7;
>
> template <class T> struct promotion_classify { static const int type_code=other_code; };
> template <class T> struct promotion_classify< const T> : public promotion_classify<T> {};
> template <> struct promotion_classify <bool> { static const int type_code=bool_code; };
> template <> struct promotion_classify <char> { static const int type_code=char_code; };
> template <> struct promotion_classify <unsigned char> { static const int type_code=uchar_code; };
> template <> struct promotion_classify <short> { static const int type_code=short_code; };
> template <> struct promotion_classify <unsigned short> { static const int type_code=ushort_code; };
> template <> struct promotion_classify <int> { static const int type_code=int_code; };
> template <> struct promotion_classify <unsigned int> { static const int type_code=uint_code; };
> template <> struct promotion_classify <long> { static const int type_code=long_code; };
> template <> struct promotion_classify <unsigned long> { static const int type_code=ulong_code; };
> template <> struct promotion_classify <float> { static const int type_code=float_code; };
> template <> struct promotion_classify <double> { static const int type_code=double_code; };
>
> // determine presidence
> template <class T1,bool, bool> struct arithmetic_promote_check
> { typedef T1 result_type; };
> template <class T1> struct arithmetic_promote_check<T1,true,false>
> { typedef int result_type; };
> template <class T1> struct arithmetic_promote_check<T1,false,true>
> { typedef long int result_type; };
>
> template <class T1> struct arithmetic_promote
> { typedef typename arithmetic_promote_check<T1,
> (promotion_classify<T1>::type_code<int_code),
> (promotion_classify<T1>::type_code==int_code)
> >::result_type result_type; };
>
> template <class T1, class T2, bool> struct arithmetic_presidence_check
> { typedef typename arithmetic_promote<T1>::result_type result_type; };
> template <class T1, class T2> struct arithmetic_presidence_check<T1,T2,false>
> { typedef typename arithmetic_promote<T2>::result_type result_type; };
>
> template <class T1, class T2> struct arithmetic_presidence
> { typedef typename arithmetic_presidence_check< T1, T2,
> (promotion_classify<T1>::type_code>promotion_classify<T2>::type_code) >::result_type result_type;
>
> #endif
> _______________________________________________
> libsigc-list mailing list
> libsigc-list gnome org
> http://mail.gnome.org/mailman/listinfo/libsigc-list
--
murrayc murrayc com
www.murrayc.com
www.openismus.com
[Date Prev][
Date Next] [Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]