Date: Tue, 10 Mar 2020 00:03:57 -0400
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;
}
#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-09 23:06:45