C++ Logo

STD-PROPOSALS

Advanced search

Subject: Re: [std-proposals] Generic template 'this' + new for_each_member() template template functor
From: Phil Bouchard (phil_at_[hidden])
Date: 2020-03-11 06:34:31


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
>>>>>>>>>


STD-PROPOSALS list run by herb.sutter at gmail.com

Standard Proposals Archives on Google Groups