C++ Logo

std-proposals

Advanced search

Re: Generic template 'this' + new for_each_member() template template functor

From: Phil Bouchard <phil_at_[hidden]>
Date: Thu, 12 Mar 2020 17:24:25 -0400
Again, here is a very powerful example with different numeric types,
their precedence with their regular and infix operators implemented only
once:


namespace numeric
{

template <typename Class, typename T>
     inline Class::Class(T const & v) : value(v.value)
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;
     }

template <typename Class, typename T>
     inline T Class::operator + (T const & v) const
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         T res;

         res.value = value + v.value;

         return res;
     }

template <typename Class, typename T>
     inline T Class::operator - (T const & v) const
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         T res;

         res.value = value - v.value;

         return res;
     }

template <typename Class, typename T>
     inline T Class::operator * (T const & v) const
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         T res;

         res.value = value * v.value;

         return res;
     }

template <typename Class, typename T>
     inline T Class::operator / (T const & v) const
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         T res;

         res.value = value / v.value;

         return res;
     }

template <typename Class, typename T>
     inline T & Class::operator += (T const & v)
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         * this = this->operator + (v);

         return * this;
     }

template <typename Class, typename T>
     inline T & Class::operator -= (T const & v)
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         * this = this->operator - (v);

         return * this;
     }

template <typename Class, typename T>
     inline T & Class::operator *= (T const & v)
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         * this = this->operator * (v);

         return * this;
     }

template <typename Class, typename T>
     inline T & Class::operator /= (T const & v)
     {
         std::clog << __PRETTY_FUNCTION__ << std::endl;

         * this = this->operator / (v);

         return * this;
     }

struct int_t;
struct double_t;
struct long_double_t;

struct int_t
{
     int value;

     int_t(int v) : value(v) {}

     int_t(int_t const & v) = generic;

     int_t operator + (int_t const & v) const = generic;
     int_t operator - (int_t const & v) const = generic;
     int_t operator * (int_t const & v) const = generic;
     int_t operator / (int_t const & v) const = generic;

     double_t operator + (double_t const & v) const = generic;
     double_t operator - (double_t const & v) const = generic;
     double_t operator * (double_t const & v) const = generic;
     double_t operator / (double_t const & v) const = generic;

     long_double_t operator + (long_double_t const & v) const = generic;
     long_double_t operator - (long_double_t const & v) const = generic;
     long_double_t operator * (long_double_t const & v) const = generic;
     long_double_t operator / (long_double_t const & v) const = generic;

     int_t & operator += (int_t const & v) = generic;
     int_t & operator -= (int_t const & v) = generic;
     int_t & operator *= (int_t const & v) = generic;
     int_t & operator /= (int_t const & v) = generic;
};

struct double_t
{
     double value;

     double_t(double v) : value(v) {}

     double_t(int_t const & v) = generic;
     double_t(double_t const & v) = generic;

     double_t operator + (double_t const & v) const = generic;
     double_t operator - (double_t const & v) const = generic;
     double_t operator * (double_t const & v) const = generic;
     double_t operator / (double_t const & v) const = generic;

     long_double_t operator + (long_double_t const & v) const = generic;
     long_double_t operator - (long_double_t const & v) const = generic;
     long_double_t operator * (long_double_t const & v) const = generic;
     long_double_t operator / (long_double_t const & v) const = generic;

     double_t & operator += (int_t const & v) = generic;
     double_t & operator -= (int_t const & v) = generic;
     double_t & operator *= (int_t const & v) = generic;
     double_t & operator /= (int_t const & v) = generic;

     double_t & operator += (double_t const & v) = generic;
     double_t & operator -= (double_t const & v) = generic;
     double_t & operator *= (double_t const & v) = generic;
     double_t & operator /= (double_t const & v) = generic;
};

struct long_double_t
{
     long double value;

     long_double_t(long double v) : value(v) {}

     long_double_t(int_t const & v) = generic;
     long_double_t(double_t const & v) = generic;
     long_double_t(long_double_t const & v) = generic;

     long_double_t operator + (long_double_t const & v) const = generic;
     long_double_t operator - (long_double_t const & v) const = generic;
     long_double_t operator * (long_double_t const & v) const = generic;
     long_double_t operator / (long_double_t const & v) const = generic;

     long_double_t & operator += (int_t const & v) = generic;
     long_double_t & operator -= (int_t const & v) = generic;
     long_double_t & operator *= (int_t const & v) = generic;
     long_double_t & operator /= (int_t const & v) = generic;

     long_double_t & operator += (double_t const & v) = generic;
     long_double_t & operator -= (double_t const & v) = generic;
     long_double_t & operator *= (double_t const & v) = generic;
     long_double_t & operator /= (double_t const & v) = generic;

     long_double_t & operator += (long_double_t const & v) = generic;
     long_double_t & operator -= (long_double_t const & v) = generic;
     long_double_t & operator *= (long_double_t const & v) = generic;
     long_double_t & operator /= (long_double_t const & v) = generic;
};

}

using numeric::int_t;
using numeric::double_t;
using numeric::long_double_t;

-- 
*Phil Bouchard*
Founder
C.: (819) 328-4743
Fornux Logo <http://www.fornux.com>
On 3/11/20 7:34 AM, Phil Bouchard wrote:
>
> To go back to the generic template 'this', here is another useful 
> example that centralizes mathematical operations:
>
> // What the user sees:
>
> struct A
> {
>     int value;
>
>     A(A const & a) : value(a.value)
>     {
>     }
>
>     A & operator += (A const & a)
>     {
>         value += a.value;
>
>         return * this;
>     }
>
>     A & operator -= (A const & a)
>     {
>         value -= a.value;
>
>         return * this;
>     }
>
>     A & operator *= (A const & a)
>     {
>         value *= a.value;
>
>         return * this;
>     }
>
>     A & operator /= (A const & a)
>     {
>         value /= a.value;
>
>         return * this;
>     }
>
>     A & operator = (A const & a) = generic; // the 'generic' keyword 
> could be used to hint the compiler of our intents
>
>     A operator + (A const & a) const = generic;
>     A operator - (A const & a) const = generic;
>     A operator * (A const & a) const = generic;
>     A operator / (A const & a) const = generic;
> };
>
>
> // Some "generic" header:
>
> template <typename Class>
>     Class & Class::operator = (Class const & c)
>     {
>         ~Class();
>
>         new (this) Class(c);
>
>         return * this;
>     }
>
> template <typename Class>
>     Class Class::operator + (Class const & c) const
>     {
>         Class r(* this);
>
>         r += c;
>
>         return r;
>     }
>
> template <typename Class>
>     Class Class::operator - (Class const & c) const
>     {
>         Class r(* this);
>
>         r -= c;
>
>         return r;
>     }
>
> template <typename Class>
>     Class Class::operator * (Class const & c) const
>     {
>         Class r(* this);
>
>         r *= c;
>
>         return r;
>     }
>
> template <typename Class>
>     Class Class::operator / (Class const & c) const
>     {
>         Class r(* this);
>
>         r /= c;
>
>         return r;
>     }
>
>
> -- 
>
> *Phil Bouchard*
> Founder
> C.: (819) 328-4743
>
> Fornux Logo <http://www.fornux.com>
>
>
> On 3/10/20 10:00 PM, Phil Bouchard wrote:
>>
>> Regarding the for_each_member() functor, here is a possible 
>> implementation:
>>
>> #include <iostream>
>>
>> using namespace std;
>>
>>
>> template <typename F>
>>     inline ostream & print(F && f, char const * n, ostream & out)
>>     {
>>         out << n;
>>
>>         return out;
>>     }
>>
>> template <typename F>
>>     inline ostream & print(F && f, char const * n, char const * t, 
>> ostream & out)
>>     {
>>         out << n << " = " << t;
>>
>>         return out;
>>     }
>>
>> template <typename F>
>>     inline ostream & print(F && f, char const * n, int const t, 
>> ostream & out)
>>     {
>>         out << n << " = " << t;
>>
>>         return out;
>>     }
>>
>> template <typename F, typename T>
>>     inline ostream & print(F && f, char const * n, T const & t, 
>> ostream & out)
>>     {
>>         f.begin(n, t, out);
>>         typename T::template for_each_member<F, 
>> ostream>()(forward<F>(f), t, out);
>>         f.end(n, t, out);
>>
>>         return out;
>>     }
>>
>>
>> // New "pretty" header:
>>
>> struct pretty
>> {
>>     size_t s;
>>     char c;
>>
>>     pretty(size_t s = 0, char c = '\t') : s(s), c(c)
>>     {
>>     }
>>
>>     ostream & indent(ostream & out)
>>     {
>>         for (size_t i = 0; i < s; ++ i)
>>             out << c;
>>
>>         return out;
>>     }
>>
>>     template <typename T>
>>         void begin(char const * n, T const & t, ostream & out)
>>         {
>>             out << n << " = " << endl;
>>             indent(out) << "{" << endl;
>>
>>             ++ s;
>>         }
>>
>>     template <typename T>
>>         void end(char const * n, T const & t, ostream & out)
>>         {
>>             -- s;
>>
>>             indent(out) << "}";
>>         }
>>
>>     template <typename T>
>>         void operator () (char const * n, T const & t, size_t i, 
>> size_t e, ostream & out)
>>         {
>>             indent(out);
>>
>>             print(* this, n, t, out);
>>
>>             if (i != e - 1)
>>                 out << ',';
>>
>>             out << endl;
>>         }
>> };
>>
>>
>> struct sql
>> {
>>     template <typename T>
>>         void begin(char const * n, T const & t, ostream & out) const
>>         {
>>             out << "SELECT ";
>>         }
>>
>>     template <typename T>
>>         void end(char const * n, T const & t, ostream & out) const
>>         {
>>             out << " FROM " << n << ";";
>>         }
>>
>>     template <typename T>
>>         void operator () (char const * n, T const & t, size_t i, 
>> size_t e, ostream & out) const
>>         {
>>             print(* this, n, out);
>>
>>             if (i != e - 1)
>>                 out << ", ";
>>         }
>> };
>>
>>
>> // Usage example:
>>
>> struct A
>> {
>>     int a = 0;
>>     int b = 1;
>>     int c = 2;
>>
>>     // Generated by the compiler:
>>     template <typename F, typename ...T>
>>         struct for_each_member
>>         {
>>             void operator () (F && f, A const & a, T & ...t)
>>             {
>>                 f("a", a.a, 0, 3, t...);
>>                 f("b", a.b, 1, 3, t...);
>>                 f("c", a.c, 2, 3, t...);
>>             }
>>         };
>> };
>>
>>
>> struct B
>> {
>>     int d = 0;
>>     int e = 1;
>>     A f = A();
>>
>>     // Generated by the compiler:
>>     template <typename F, typename ...T>
>>         struct for_each_member
>>         {
>>             void operator () (F && f, B const & b, T & ...t)
>>             {
>>                 f("d", b.d, 0, 3, t...);
>>                 f("e", b.e, 1, 3, t...);
>>                 f("f", b.f, 2, 3, t...);
>>             }
>>         };
>> };
>>
>>
>> int main()
>> {
>>     B b;
>>
>>     cout << "Pretty print:" << endl;
>>     print(pretty(), "b", b, cout) << endl;
>>     cout << endl;
>>
>>     cout << "SQL print:" << endl;
>>     print(sql(), "b", b, cout) << endl;
>> }
>>
>>
>> Outputs:
>>
>> Pretty print:
>> b =
>> {
>>         d = 0,
>>         e = 1,
>>         f =
>>         {
>>                 a = 0,
>>                 b = 1,
>>                 c = 2
>>         }
>> }
>>
>> SQL print:
>> SELECT d, e, f FROM b;
>>
>> -- 
>>
>> *Phil Bouchard*
>> Founder
>> C.: (819) 328-4743
>>
>> Fornux Logo <http://www.fornux.com>
>>
>>
>> On 3/10/20 1:56 PM, Phil Bouchard wrote:
>>> Even better: for_each_member<> should be nested inside their 
>>> respective class (i.e. typename A::for_each_member<>), this way we 
>>> won’t pollute the global namespace at all and have a million error 
>>> messages when something goes wrong.
>>>
>>> Also we could have:
>>> ...::for_each_member<>
>>> ...::for_each_public_member<>
>>> ...::for_each_private_member<>
>>> ...::for_each_protected_member<>
>>>
>>> -- 
>>>
>>> *Phil Bouchard*
>>> Founder
>>> C.: (819) 328-4743 <tel:(819)%20328-4743>
>>>
>>> Fornux Logo <http://www.fornux.com/>
>>>
>>> On Mar 10, 2020, at 8:50 AM, Phil Bouchard <phil_at_[hidden] 
>>> <mailto:phil_at_[hidden]>> wrote:
>>>
>>>> Here are little corrections:
>>>>
>>>> #include <iostream>
>>>> #include <functional>
>>>>
>>>> using namespace std;
>>>>
>>>>
>>>> // Compiler internal:
>>>>
>>>> template <typename F, typename ...T>
>>>>     struct for_each_member;
>>>>
>>>> template <typename F, typename ...T>
>>>>     inline void make_for_each_member(F && f, T && ...t)
>>>>     {
>>>>         for_each_member<F, T...>()(forward<F>(f), forward<T>(t)...);
>>>>     }
>>>>
>>>>
>>>> // New "pretty" header:
>>>>
>>>> struct pretty
>>>> {
>>>>     size_t n;
>>>>
>>>>     pretty(size_t n = 0):n(n) {}
>>>>
>>>>     ostream & indent(size_t n, ostream & out)
>>>>     {
>>>>         for (size_t i = 0; i < n * 4; ++ i)
>>>>             out << ' ';
>>>>
>>>>         return out;
>>>>     }
>>>>
>>>>     template <typename T>
>>>>         void operator () (T const & t, size_t i, size_t e, size_t 
>>>> n, ostream & out)
>>>>         {
>>>>             if (i == 0)
>>>>                 indent(n, out) << '{' << endl;
>>>>
>>>>             indent(n + 1, out) << t;
>>>>
>>>>             if (i != e - 1)
>>>>                 out << ',';
>>>>
>>>>             out << endl;
>>>>
>>>>             if (i == e - 1)
>>>>                 indent(n, out) << '}';
>>>>         }
>>>> };
>>>>
>>>> // New "print" header:
>>>>
>>>> template <typename T, typename F>
>>>>     inline ostream & T::print(F && f, ostream & out)
>>>>     {
>>>>         make_for_each_member(f, * this, cout);
>>>>
>>>>         return out;
>>>>     }
>>>>
>>>>
>>>> // Usage example:
>>>>
>>>> struct A
>>>> {
>>>>     int a = 0, b = 1, c = 2;
>>>>
>>>>     // Capabilities:
>>>>     template <typename F>
>>>>         ostream & print(F && f, ostream & out); // only a 
>>>> declaration needed if "print" header included
>>>> };
>>>>
>>>>
>>>> // Generated by the compiler:
>>>>
>>>> template <typename F, typename ...T>
>>>>     struct for_each_member<F, A, T...>
>>>>     {
>>>>         void operator () (F && f, A && a, T && ...t)
>>>>         {
>>>>             f(forward<decltype(a.a)>(a.a), 0, 3, forward<T>(t)...);
>>>>             f(forward<decltype(a.b)>(a.b), 1, 3, forward<T>(t)...);
>>>>             f(forward<decltype(a.c)>(a.c), 2, 3, forward<T>(t)...);
>>>>         }
>>>>     };
>>>>
>>>>
>>>> int main()
>>>> {
>>>>     A a;
>>>>
>>>>     a.print(pretty(), cout) << endl;
>>>>     a.print(binary(), cout) << endl;
>>>>     a.print(sql(), cout) << endl;
>>>> }
>>>>
>>>>
>>>> -- 
>>>>
>>>> *Phil Bouchard*
>>>> Founder
>>>> C.: (819) 328-4743
>>>>
>>>> Fornux Logo <http://www.fornux.com>
>>>>
>>>>
>>>> On 3/10/20 12:03 AM, Phil Bouchard wrote:
>>>>>
>>>>> Here's a prettier example, without the template template functor:
>>>>>
>>>>> #include <iostream>
>>>>> #include <functional>
>>>>>
>>>>> using namespace std;
>>>>>
>>>>>
>>>>> // Compiler internal:
>>>>>
>>>>> template <typename F, typename ...T>
>>>>>     struct for_each_member;
>>>>>
>>>>> template <typename F, typename ...T>
>>>>>     inline void make_for_each_member(F && f, T && ...t)
>>>>>     {
>>>>>         for_each_member<F, T...>()(forward<F>(f), forward<T>(t)...);
>>>>>     }
>>>>>
>>>>>
>>>>> // New "pretty_print" header:
>>>>>
>>>>> struct pretty_print
>>>>> {
>>>>>     size_t n;
>>>>>
>>>>>     pretty_print(size_t n = 0):n(n) {}
>>>>>
>>>>>     ostream & indent(size_t n, ostream & out)
>>>>>     {
>>>>>         for (size_t i = 0; i < n * 4; ++ i)
>>>>>             out << ' ';
>>>>>
>>>>>         return out;
>>>>>     }
>>>>>
>>>>>     template <typename T>
>>>>>         void operator () (T const & t, size_t i, size_t e, size_t 
>>>>> n, ostream & out)
>>>>>         {
>>>>>             if (i == 0)
>>>>>                 indent(n, out) << '{' << endl;
>>>>>
>>>>>             indent(n + 1, out) << t;
>>>>>
>>>>>             if (i != e - 1)
>>>>>                 out << ',';
>>>>>
>>>>>             out << endl;
>>>>>
>>>>>             if (i == e - 1)
>>>>>                 indent(n, out) << '}';
>>>>>         }
>>>>> };
>>>>>
>>>>> template <typename T>
>>>>>     inline ostream & T::pretty_print(size_t n, ostream & out)
>>>>>     {
>>>>>         pretty_print f(n);
>>>>>
>>>>> make_for_each_member<pretty_print>(f, T(), cout);
>>>>>
>>>>>         return out;
>>>>>     }
>>>>>
>>>>>
>>>>> // Usage example:
>>>>>
>>>>> struct A
>>>>> {
>>>>>     int a = 0, b = 1, c = 2;
>>>>>
>>>>>     // Capabilities:
>>>>>     ostream & pretty_print(size_t n, ostream & out); // only a 
>>>>> declaration needed if "pretty_print" header included
>>>>>     ostream & binary_print(ostream & out); // same here
>>>>>     ostream & sql_print(ostream & out); // same
>>>>> };
>>>>>
>>>>>
>>>>> // Generated by the compiler:
>>>>>
>>>>> template <typename F, typename ...T>
>>>>>     struct for_each_member<F, A, T...>
>>>>>     {
>>>>>         void operator () (F && f, A && a, T && ...t)
>>>>>         {
>>>>>             f(forward<decltype(a.a)>(a.a), 0, 3, forward<T>(t)...);
>>>>>             f(forward<decltype(a.b)>(a.b), 1, 3, forward<T>(t)...);
>>>>>             f(forward<decltype(a.c)>(a.c), 2, 3, forward<T>(t)...);
>>>>>         }
>>>>>     };
>>>>>
>>>>>
>>>>> int main()
>>>>> {
>>>>>     A a;
>>>>>
>>>>>     a.pretty_print(0, cout) << endl;
>>>>> }
>>>>>
>>>>> -- 
>>>>>
>>>>> *Phil Bouchard*
>>>>> Founder
>>>>> C.: (819) 328-4743
>>>>>
>>>>> Fornux Logo <http://www.fornux.com>
>>>>>
>>>>>
>>>>> On 3/9/20 8:44 PM, Phil Bouchard wrote:
>>>>>>
>>>>>> Here is a clean usage example:
>>>>>>
>>>>>> #include <iostream>
>>>>>> #include <functional>
>>>>>>
>>>>>> using namespace std;
>>>>>>
>>>>>>
>>>>>> // Compiler internal:
>>>>>>
>>>>>> template <template <typename> class F, typename ...T> // note the 
>>>>>> usage of the necessary template template parameter
>>>>>>     struct for_each_member;
>>>>>>
>>>>>> template <template <typename> class F, typename ...T>
>>>>>>     inline void make_for_each_member(T && ...t)
>>>>>>     {
>>>>>>         for_each_member<F, T...>()(forward<T>(t)...);
>>>>>>     }
>>>>>>
>>>>>>
>>>>>> // New "pretty_print" header:
>>>>>>
>>>>>> template <typename T>
>>>>>>     struct pretty_print
>>>>>>     {
>>>>>>         ostream & indent(size_t n, ostream & out)
>>>>>>         {
>>>>>>             for (size_t i = 0; i < n * 4; ++ i)
>>>>>>                 out << ' ';
>>>>>>
>>>>>>             return out;
>>>>>>         }
>>>>>>
>>>>>>         void operator () (T const & t, size_t i, size_t e, size_t 
>>>>>> n, ostream & out)
>>>>>>         {
>>>>>>             if (i == 0)
>>>>>>                 indent(n, out) << '{' << endl;
>>>>>>
>>>>>>             indent(n + 1, out) << t;
>>>>>>
>>>>>>             if (i != e - 1)
>>>>>>                 out << ',';
>>>>>>
>>>>>>             out << endl;
>>>>>>
>>>>>>             if (i == e - 1)
>>>>>>                 indent(n, out) << '}';
>>>>>>         }
>>>>>>     };
>>>>>>
>>>>>> template <typename T>
>>>>>>     inline ostream & T::pretty_print(ostream & out)
>>>>>>     {
>>>>>>         size_t indent = 0;
>>>>>>
>>>>>> make_for_each_member<pretty_print>(T(), indent, cout);
>>>>>>
>>>>>>         return out;
>>>>>>     }
>>>>>>
>>>>>>
>>>>>> // Usage example (what the user will only see):
>>>>>>
>>>>>> struct A
>>>>>> {
>>>>>>     int a = 0, b = 1, c = 2;
>>>>>>
>>>>>>     ostream & pretty_print(ostream & out); // only a declaration 
>>>>>> needed if "pretty_print" header included
>>>>>> };
>>>>>>
>>>>>>
>>>>>> // Generated by the compiler:
>>>>>>
>>>>>> template <template <typename> class F, typename ...T>
>>>>>>     struct for_each_member<F, A, T...>
>>>>>>     {
>>>>>>         void operator () (A && a, T && ...t)
>>>>>>         {
>>>>>> F<decltype(a.a)>()(forward<decltype(a.a)>(a.a), 0, 3, 
>>>>>> forward<T>(t)...);
>>>>>> F<decltype(a.b)>()(forward<decltype(a.b)>(a.b), 1, 3, 
>>>>>> forward<T>(t)...);
>>>>>> F<decltype(a.c)>()(forward<decltype(a.c)>(a.c), 2, 3, 
>>>>>> forward<T>(t)...);
>>>>>>         }
>>>>>>     };
>>>>>>
>>>>>>
>>>>>> int main()
>>>>>> {
>>>>>>     A a;
>>>>>>
>>>>>>     a.pretty_print(cout) << endl;
>>>>>> }
>>>>>>
>>>>>>
>>>>>> Other applications of for_each_member() can be:
>>>>>>
>>>>>> - comparisons,
>>>>>>
>>>>>> - changing properties of filtered mutable member variables,
>>>>>>
>>>>>> - generic debug functions changed on-the-fly at one place only,
>>>>>>
>>>>>> - easily apply textual and binary I/O operations to huge structures,
>>>>>>
>>>>>> - easily apply database operations to huge structures,
>>>>>>
>>>>>> - automate the mapping of structures to a user-interface generator,
>>>>>>
>>>>>> - ...
>>>>>>
>>>>>>
>>>>>> -- 
>>>>>>
>>>>>> *Phil Bouchard*
>>>>>> Founder
>>>>>> C.: (819) 328-4743
>>>>>>
>>>>>> Fornux Logo <http://www.fornux.com>
>>>>>>
>>>>>>
>>>>>> On 3/9/20 10:56 AM, Phil Bouchard wrote:
>>>>>>> ... Also we could limit generic ‘this’ overloads to specific 
>>>>>>> namespaces:
>>>>>>>
>>>>>>> template <typename Class>
>>>>>>>     ostream & boost::detail::Class::operator << (ostream & out) 
>>>>>>> { ... }
>>>>>>>
>>>>>>> -- 
>>>>>>>
>>>>>>> *Phil Bouchard*
>>>>>>> Founder
>>>>>>> C.: (819) 328-4743 <tel:(819)%20328-4743>
>>>>>>>
>>>>>>> Fornux Logo <http://www.fornux.com/>
>>>>>>>
>>>>>>> On Mar 8, 2020, at 7:36 PM, Phil Bouchard <phil_at_[hidden] 
>>>>>>> <mailto:phil_at_[hidden]>> wrote:
>>>>>>>
>>>>>>>> ... And only the classes with the proper declarations would 
>>>>>>>> take advantage of the generic template 'this':
>>>>>>>>
>>>>>>>>
>>>>>>>> -- 
>>>>>>>>
>>>>>>>> *Phil Bouchard*
>>>>>>>> Founder
>>>>>>>> C.: (819) 328-4743
>>>>>>>>
>>>>>>>> Fornux Logo <http://www.fornux.com>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 3/8/20 7:34 PM, Phil Bouchard wrote:
>>>>>>>>>
>>>>>>>>> What I have in mind is to clean up the dispatch fiasco that is 
>>>>>>>>> done with either the constructors or the cast operator right 
>>>>>>>>> now. Conversions, comparisons, ... should be simplified as 
>>>>>>>>> well. For example:
>>>>>>>>>
>>>>>>>>> struct X
>>>>>>>>>
>>>>>>>>> {
>>>>>>>>>
>>>>>>>>>     int value;
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>     template <typename T>
>>>>>>>>>
>>>>>>>>>         X(T const & T);
>>>>>>>>>
>>>>>>>>>     template <typename T>
>>>>>>>>>
>>>>>>>>>         operator T ();
>>>>>>>>>
>>>>>>>>> };
>>>>>>>>>
>>>>>>>>> struct Y
>>>>>>>>>
>>>>>>>>> {
>>>>>>>>>
>>>>>>>>>     int value;
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>     template <typename T>
>>>>>>>>>
>>>>>>>>>         Y(T const & T);
>>>>>>>>>
>>>>>>>>>     template <typename T>
>>>>>>>>>
>>>>>>>>>         operator T ();
>>>>>>>>>
>>>>>>>>> };
>>>>>>>>>
>>>>>>>>> template <typename Class, typename T>
>>>>>>>>>
>>>>>>>>>     inline Class::operator T () { return T(* this); } // 
>>>>>>>>> generic constructor wrapper
>>>>>>>>>
>>>>>>>>> template <typename Class, typename T>
>>>>>>>>>
>>>>>>>>>     inline Class::Class(T const &t) { value = t.value; } // 
>>>>>>>>> cast operation really done here
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> And normal specializations here:
>>>>>>>>>
>>>>>>>>> template <typename T>
>>>>>>>>>
>>>>>>>>>     inline X::X(T const &t) { value = t.value; } // 
>>>>>>>>> specialized cast operation done here
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Also if we had a way to iterate all members (which would be 
>>>>>>>>> another important proposal) then we could also have a generic 
>>>>>>>>> "operator <<" as well:
>>>>>>>>>
>>>>>>>>> template <typename Class>
>>>>>>>>>
>>>>>>>>>     ostream & Class::operator << (ostream & out)
>>>>>>>>>
>>>>>>>>>     {
>>>>>>>>>
>>>>>>>>>         for (member_iterator<Class> i = 
>>>>>>>>> member_iterator<Class>::begin(); i != 
>>>>>>>>> member_iterator<Class>::end(); ++ i)
>>>>>>>>>
>>>>>>>>>         {
>>>>>>>>>
>>>>>>>>>             if (i != member_iterator<Class>::begin())
>>>>>>>>>
>>>>>>>>>                 out << ", ";
>>>>>>>>>
>>>>>>>>>             out << this->*i;
>>>>>>>>>
>>>>>>>>>         }
>>>>>>>>>
>>>>>>>>>         return out;
>>>>>>>>>
>>>>>>>>>     }
>>>>>>>>>
>>>>>>>>> The aforementioned should also remove the need for these 
>>>>>>>>> global friend function overloads.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> -- 
>>>>>>>>>
>>>>>>>>> *Phil Bouchard*
>>>>>>>>> Founder
>>>>>>>>> C.: (819) 328-4743
>>>>>>>>>
>>>>>>>>> Fornux Logo <http://www.fornux.com>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 3/8/20 6:03 PM, Jake Arkinstall wrote:
>>>>>>>>>> For me, this approach has some merits, but this particular 
>>>>>>>>>> example is something that, to me, makes much more sense as a 
>>>>>>>>>> free function.
>>>>>>>>>>
>>>>>>>>>> Do you have further examples?
>>>>>>>>>>
>>>>>>>>>> On Sun, 8 Mar 2020, 21:55 Phil Bouchard via Std-Proposals, 
>>>>>>>>>> <std-proposals_at_[hidden] 
>>>>>>>>>> <mailto:std-proposals_at_[hidden]>> wrote:
>>>>>>>>>>
>>>>>>>>>>     Well I believe a proposal should be open for debate, just
>>>>>>>>>>     like a thesis.
>>>>>>>>>>
>>>>>>>>>>     We both agree these overloads should be simplified but we
>>>>>>>>>>     disagree on the syntax.
>>>>>>>>>>
>>>>>>>>>>     I saw the recursive lambda thing and I think I already
>>>>>>>>>>     talked to you before regarding CV overloads but we were
>>>>>>>>>>     proposing the following syntax:
>>>>>>>>>>
>>>>>>>>>>     struct A
>>>>>>>>>>
>>>>>>>>>>     {
>>>>>>>>>>
>>>>>>>>>>         template <bool BC>
>>>>>>>>>>
>>>>>>>>>>             void foo() bool<BC>
>>>>>>>>>>
>>>>>>>>>>             {
>>>>>>>>>>
>>>>>>>>>>             }
>>>>>>>>>>
>>>>>>>>>>     };
>>>>>>>>>>
>>>>>>>>>>     And regarding the this generic overloading I still
>>>>>>>>>>     believe the following syntax is cleaner:
>>>>>>>>>>
>>>>>>>>>>     struct A
>>>>>>>>>>
>>>>>>>>>>     {
>>>>>>>>>>
>>>>>>>>>>         template <typename T>
>>>>>>>>>>
>>>>>>>>>>             bool compare(T const &);
>>>>>>>>>>
>>>>>>>>>>     };
>>>>>>>>>>
>>>>>>>>>>     template <typename C, typename T>
>>>>>>>>>>
>>>>>>>>>>         void C::compare(C const &)
>>>>>>>>>>
>>>>>>>>>>         {
>>>>>>>>>>
>>>>>>>>>>             ...
>>>>>>>>>>
>>>>>>>>>>         }
>>>>>>>>>>
>>>>>>>>>>     Because with your syntax I could technically reassign "self":
>>>>>>>>>>
>>>>>>>>>>     struct A
>>>>>>>>>>
>>>>>>>>>>     {
>>>>>>>>>>
>>>>>>>>>>         template <typename C, typename T>
>>>>>>>>>>
>>>>>>>>>>             bool compare(this C & c, T const &);
>>>>>>>>>>
>>>>>>>>>>     };
>>>>>>>>>>
>>>>>>>>>>     template <typename C, typename T>
>>>>>>>>>>
>>>>>>>>>>         bool C::compare(this C & c, T const &) // redundant C
>>>>>>>>>>     here
>>>>>>>>>>
>>>>>>>>>>         {
>>>>>>>>>>
>>>>>>>>>>             static C sc = C();
>>>>>>>>>>
>>>>>>>>>>             c = sc; // in theory we could do this unless you
>>>>>>>>>>     patch the compilers with a new error for that specific case
>>>>>>>>>>
>>>>>>>>>>         }
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>     -- 
>>>>>>>>>>
>>>>>>>>>>     *Phil Bouchard*
>>>>>>>>>>     Founder
>>>>>>>>>>     C.: (819) 328-4743
>>>>>>>>>>
>>>>>>>>>>     Fornux Logo <http://www.fornux.com>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>     On 3/8/20 5:37 AM, Gašper Ažman wrote:
>>>>>>>>>>>     I meant that you should consider the incremental value
>>>>>>>>>>>     of your proposal over p0847, which is on track for c++23
>>>>>>>>>>>     unless serious issues crop up
>>>>>>>>>>>
>>>>>>>>>>>     On Sat, Mar 7, 2020, 19:04 Phil Bouchard
>>>>>>>>>>>     <phil_at_[hidden] <mailto:phil_at_[hidden]>> wrote:
>>>>>>>>>>>
>>>>>>>>>>>         The syntaxes are way different:
>>>>>>>>>>>
>>>>>>>>>>>         http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0847r4.html
>>>>>>>>>>>
>>>>>>>>>>>         In your case the compiler will have to change all of
>>>>>>>>>>>         its rules for the number of parameters "operator"
>>>>>>>>>>>         overloads. For example:
>>>>>>>>>>>
>>>>>>>>>>>         struct A
>>>>>>>>>>>
>>>>>>>>>>>         {
>>>>>>>>>>>
>>>>>>>>>>>             int value;
>>>>>>>>>>>
>>>>>>>>>>>             ...
>>>>>>>>>>>
>>>>>>>>>>>             template <typename Self>
>>>>>>>>>>>
>>>>>>>>>>>                 bool operator < (this Self && self, A const
>>>>>>>>>>>         & a) // 2 parameters... ok
>>>>>>>>>>>
>>>>>>>>>>>                 {
>>>>>>>>>>>
>>>>>>>>>>>         return self.value < a.value;
>>>>>>>>>>>
>>>>>>>>>>>                 }
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>                 bool operator < (A const & a) // 1
>>>>>>>>>>>         parameter... ok
>>>>>>>>>>>
>>>>>>>>>>>                 {
>>>>>>>>>>>
>>>>>>>>>>>         return value < a.value;
>>>>>>>>>>>
>>>>>>>>>>>                 }
>>>>>>>>>>>
>>>>>>>>>>>         };
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>         -- 
>>>>>>>>>>>
>>>>>>>>>>>         *Phil Bouchard*
>>>>>>>>>>>         Founder
>>>>>>>>>>>         C.: (819) 328-4743
>>>>>>>>>>>
>>>>>>>>>>>         Fornux Logo <http://www.fornux.com>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>         On 3/7/20 1:35 PM, Gašper Ažman wrote:
>>>>>>>>>>>>         P0847
>>>>>>>>>>>>
>>>>>>>>>>>>         On Sat, Mar 7, 2020, 18:33 Phil Bouchard via
>>>>>>>>>>>>         Std-Proposals <std-proposals_at_[hidden]
>>>>>>>>>>>>         <mailto:std-proposals_at_[hidden]>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>             Alright, I'm pretty sure this is not
>>>>>>>>>>>>             implemented yet. Suppose you have:
>>>>>>>>>>>>
>>>>>>>>>>>>             struct A
>>>>>>>>>>>>
>>>>>>>>>>>>             {
>>>>>>>>>>>>
>>>>>>>>>>>>                 int value;
>>>>>>>>>>>>
>>>>>>>>>>>>                 ...
>>>>>>>>>>>>
>>>>>>>>>>>>             template <typename T>
>>>>>>>>>>>>
>>>>>>>>>>>>                     int compare(T const & t) const;
>>>>>>>>>>>>
>>>>>>>>>>>>             }
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>             struct B
>>>>>>>>>>>>
>>>>>>>>>>>>             {
>>>>>>>>>>>>
>>>>>>>>>>>>                 int value;
>>>>>>>>>>>>
>>>>>>>>>>>>                 ...
>>>>>>>>>>>>
>>>>>>>>>>>>             template <typename T>
>>>>>>>>>>>>
>>>>>>>>>>>>                     int compare(T const & t) const;
>>>>>>>>>>>>
>>>>>>>>>>>>             }
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>             Then a generic way to define the same
>>>>>>>>>>>>             functionality for all classes would be to have
>>>>>>>>>>>>             a "template 'this'":
>>>>>>>>>>>>
>>>>>>>>>>>>             template <typename C, typename T>
>>>>>>>>>>>>
>>>>>>>>>>>>             inline int C::compare(T const & t) const
>>>>>>>>>>>>
>>>>>>>>>>>>                     {
>>>>>>>>>>>>
>>>>>>>>>>>>             return value == t.value ? 0 : value < t.value ?
>>>>>>>>>>>>             -1 : 1;
>>>>>>>>>>>>
>>>>>>>>>>>>                     }
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>             (Please include my email address in your replies)
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>             -- 
>>>>>>>>>>>>
>>>>>>>>>>>>             *Phil Bouchard*
>>>>>>>>>>>>             Founder
>>>>>>>>>>>>             C.: (819) 328-4743
>>>>>>>>>>>>
>>>>>>>>>>>>             Fornux Logo <http://www.fornux.com>
>>>>>>>>>>>>             -- 
>>>>>>>>>>>>             Std-Proposals mailing list
>>>>>>>>>>>>             Std-Proposals_at_[hidden]
>>>>>>>>>>>>             <mailto:Std-Proposals_at_[hidden]>
>>>>>>>>>>>>             https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>>>>>>>>>>
>>>>>>>>>>     -- 
>>>>>>>>>>     Std-Proposals mailing list
>>>>>>>>>>     Std-Proposals_at_[hidden]
>>>>>>>>>>     <mailto:Std-Proposals_at_[hidden]>
>>>>>>>>>>     https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>>>>>>>>

Received on 2020-03-12 16:27:14