C++ Logo

std-proposals

Advanced search

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

From: Phil Bouchard <phil_at_[hidden]>
Date: Tue, 10 Mar 2020 22:00:53 -0400
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-10 21:03:43