Date: Tue, 10 Mar 2020 08:50:08 -0400
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;
}
#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 07:52:56